检查字符串是否是Javascript正则表达式的前缀

检查字符串是否是Javascript正则表达式的前缀,javascript,regex,prefix,Javascript,Regex,Prefix,在Javascript中,我定义了一个正则表达式,现在用户正在键入一个字符串。我想告诉他,如果他继续打字,他的字符串是否仍然可以匹配RegExp,或者他是否已经走错了路。例如: var re = /a*b/; "a".isPrefixOf( re ); // true "x".isPrefixOf( re ); // false var re = /a*b/; var sInput = "a"; var reInput = new RegExp( sInput + ".*" ); reIn

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

var re = /a*b/;

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

reIntersection = re.intersect( reInput );
reIntersection.isEmpty(); // false
/a*bcd*e/
isPrefixOf
的实现是什么样子的

更新:感谢您的回答,按照brad的建议,对regex前缀进行验证似乎是一个很好的解决方法。但我仍在试图找到一个普遍的解决办法

也许这样:我们创建一个新的正则表达式,用户输入后跟
*
。这个正则表达式描述了用户仍然可以输入的所有单词。如果创建的正则表达式和原始正则表达式的交集为空,则用户已经走错了路。如果不是,他做得很好。例如:

var re = /a*b/;

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

reIntersection = re.intersect( reInput );
reIntersection.isEmpty(); // false
/a*bcd*e/
intersect()
返回一个新的正则表达式,该正则表达式只接受
re
reInput
都会接受的单词。该函数尚不存在,但我们可以使用“前瞻”实现它:

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

保持打开状态的是
isEmpty()
函数。我们如何检查Javascript正则表达式是否与任何单词匹配或是否为空?

首先将正则表达式定义为: var re=new RegExp(/^(此处为RegExp)$/)

在onKeypress事件中,检查regexp,如下所示:

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


清楚吗?

一种方法是挂接文本框的onKeyUp事件,然后根据正则表达式测试文本。 我的假设当然是您希望进行正则表达式匹配。 我不确定这是否正是您需要的,实际上是您的代码:

"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>

//

非常有趣的问题。在我的快速搜索中,我没有找到任何预定义的(甚至在Perl中也没有)来解决这个问题

编辑:哎哟,看起来Java有一个类似的东西叫做hitEnd()——参见Alan M的答案。hitEnd()的作用是说match()的结果(true或false)可能会被其他输入修改。《掌握正则表达式》一书说它不是很可靠(不知道为什么,第392页在谷歌图书中没有)

根据您使用的正则表达式的哪些特性,快速破解方法(如为regexp编写某种前缀):

e、 g.对于a+a*b+c,前缀将为:

a+ a+a* a+a*b+ a+a*b+c a+ a+a* a+a*b+ a+a*b+c 如果使用choice运算符、range运算符{n,m}或back references,则很难进行快速破解

也就是说,我认为好的解决方案是稍微修改匹配算法

通常使用的匹配算法是回溯算法(即使最坏的情况是指数行为,它在实践中也能很好地工作)。该算法在到达regexp结尾时成功终止(即使没有使用整个字符串)。您需要做的是修改终止条件,使其在使用所有输入时也能成功终止

也就是说,您可能必须实际使用JavaScript实现该算法。希望这将成为Jquery等库的一部分

有关该算法的更多参考资料和理论,请参阅本文:


(即使它反对回溯算法并建议基于FA的算法(但FA无法处理回溯引用))。

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

var re = /a*b/;

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

reIntersection = re.intersect( reInput );
reIntersection.isEmpty(); // false
/a*bcd*e/
前缀regex可以是:

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

这有点混乱,但我认为会很好地解决您的问题。

人们似乎在如何解释这个问题上意见分歧,因此我将用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没有类似Java的
hitEnd()的东西
方法,但可能会伪造它。如果有人知道怎么做,那就是那个明目张胆的坏蛋。

你应该更仔细地阅读这个问题。它不是问如何调用匹配器。它是问如何编写匹配器。你应该更仔细地阅读这个问题。它不是问如何调用匹配器。它是问如何编写匹配器。这就是为什么我用粗体字强调了那个注释!虽然这个问题的措辞可能会更好,但我认为这并不难理解。您希望我删除哪一票?这是一个好主意(您获得了一张赞成票),但对于更复杂的模式,我想它会很快分解。如何为以下模式创建前缀regex?/a(公元前|公元前)d/