首页 文章

检查string是否是Javascript RegExp的前缀

提问于
浏览
13

在Javascript中,我定义了一个正则表达式,现在用户正在键入一个字符串 . 我想告诉他,如果他的字符串仍然可以与RegExp匹配,如果他继续打字或者他已经走错了路 . 例如:

var re = /a*b/;

"a".isPrefixOf( re ); // true
"x".isPrefixOf( re ); // false

isPrefixOf 的实现怎么样?

Update: 感谢您的回答,正如brad建议的那样使正则表达式前缀保证似乎是一个很好的解决方法 . 但我仍在努力找到一个通用的解决方案 .

也许这样:我们使用用户输入后跟 .* 创建一个新的正则表达式 . 此正则表达式描述了用户仍可输入的所有单词 . 如果此创建的正则表达式与原始正则表达式的交集为空,则表示用户已经错误 . 如果它's not, he'做得很好 . 例如:

var re = /a*b/;
var sInput = "a";
var reInput = new RegExp( sInput + ".*" );

reIntersection = re.intersect( reInput );
reIntersection.isEmpty(); // false

intersect() 返回一个新的正则表达式,它只接受 rereInput 都接受的单词 . 该功能尚不存在,但我们可以使用预测来实现它:

RegExp.prototype.intersect = function( pattern2 ) { 
    return new RegExp( '(?=' + this.source  + ')' + pattern2.source );
}

剩下的是 isEmpty() 功能 . 如果Javascript正则表达式匹配任何单词或它是否为空,我们如何检查?

5 回答

  • 3

    人们似乎在分析他们如何解释这个问题,所以我将用Java示例来演示这个概念 .

    import java.util.regex.*;
    
    public class Test
    {
    
      public static void main(String[] args) throws Exception
      {
        tryMatch("^a*b+$", "a", "ab", "abc");
      }
    
      public static void tryMatch(String regex, String... targets)
      {
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher("");
        System.out.printf("%nregex: %s%n", regex);
        System.out.printf("target | matches() | hitEnd()%n");
        for (String str : targets)
        {
          m.reset(str);
          System.out.printf("%-6s | %-9B | %-9B%n",
              str, m.matches(), m.hitEnd());
        }
      }
    }
    

    输出:

    regex: ^a*b+$
    target | matches() | hitEnd()
    a      | FALSE     | TRUE
    ab     | TRUE      | TRUE
    abc    | FALSE     | FALSE
    

    目标字符串"a"不匹配,因为正则表达式至少需要一个 b ,但它可能是成功匹配的前缀,因此 hitEnd() 返回 true . 字符串"ab"具有匹配所需的全部内容,但如果我们在末尾添加了更多 b ,它也会匹配,因此 hitEnd() 仍会返回 true . 使用"abc"时,匹配尝试在到达目标字符串的末尾之前失败,因此正则表达式无法匹配以"abc"开头的任何字符串 .

    据我所知,Javascript没有't have anything like Java' s hitEnd() 方法,但它有可能伪造它 . 如果有人知道怎么做,那就是Flagrant Badass,Steven Levithan .

  • 4

    我认为你最好的选择是使你的正则表达式前缀 . 对于你给出的例子, /a*b/ ,我想你可能会使用 /a*b?/.test(userinput) . 对于更复杂的模式,这可能变得越来越困难,但我仍然认为可以通过将每个子表达式嵌套在一系列可选的量词中来完成( ? ) . 例如:

    /a*bcd*e/
    

    前缀正则表达式可以是:

    /a*(b(c(d*e?)?)?)?/
    

    它有点乱,但我认为会很好地解决你的问题 .

  • -1

    非常有趣的问题 . 在我的快速搜索中,我没有找到解决此问题的预定义(甚至在Perl中) .

    编辑:哎呀,似乎Java有类似的东西叫做hitEnd() - 参见Alan M的回答 . hitEnd()的作用是说match()的结果(true或false)可能会被附加输入修改 . “Mastering Regular Expressions”这本书说它不太可靠(不确定为什么,第392页在谷歌书籍中没有) .

    根据您使用的正则表达式的哪些功能,快速破解,例如编写正则表达式的某些前缀:

    例如对于a * b c,您的前缀将是:

    a+
    a+a*
    a+a*b+
    a+a*b+c
    

    并尝试将它们中的任何一个与您的字符串匹配 . 如果使用范围运算符{n,m}或反向引用,则使用选择运算符会导致此快速破解 .

    话虽这么说,我认为好的解决方案是略微修改匹配算法 .

    通常采用的匹配算法是回溯算法(即使最坏情况行为是指数的,它在实践中也能很好地工作) . 只要到达正则表达式的末尾,该算法就会成功终止(即使没有消耗掉整个字符串) . 您需要做的是修改终止条件,使其在消耗完所有输入后也成功终止 .

    话虽这么说,你可能不得不在JavaScript中实际实现该算法 . 希望这将成为Jquery等图书馆的一部分 .

    有关该算法的更多参考和理论,请查看以下文章:

    http://swtch.com/~rsc/regexp/regexp1.html

    (即使它反对回溯算法并建议基于FA的算法(但FA不能处理反向引用)) .

  • 2

    首先,将正则表达式定义为:var re = new RegExp(/ ^(regexp here)$ /);

    在onKeypress事件中,你检查正则表达式如下:

    text.match(regexp) - 其中文本是输入的字符串 .

    这个清楚吗?

  • -1

    这样做的一种方法是挂钩文本框的onKeyUp事件和 .test 反对正则表达式的文本 . My assumption is of course that you want to do a regular expression matching. 我不确定这是否正是您所需要的,实际上您的代码:

    "a".isPrefixOf( re ); // true
    

    永远不会匹配,因为它还需要一个后续的“b”字符(你可能想要修改正则表达式) . 例如,此代码将针对与此格式匹配的任何字符串进行测试:

    a-n(n)-b
    

    这是代码,将其另存为页面并将其加载到浏览器中:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="it">
    <body>
        <input type="text" size="20" id="txtData" onkeyup="showResult()" />
        <div id="dvResult" />
    </body>
    </html>
    <script type="text/javascript">
    //<![CDATA[
    
        theRegExp = /^a\-\d{1,2}\-b$/;
    
        function isPrefixOf( aText, aRegExp )
        {
            return aRegExp.test( aText );
        }
    
        function showResult()
        {
            res = document.getElementById( "dvResult" );
            res.innerHTML = isPrefixOf( document.getElementById( "txtData" ).value, theRegExp ) ? "Correct" : "Bad input";
        }
    
    //]]>
    </script>
    

相关问题