在Javascript中我定义了一个正则表达式,现在用户正在输入一个字符串。我想告诉他,如果他的字符串仍然可以与RegExp匹配,如果他继续打字或者他已经走错了路。例如:
var re = /a*b/;
"a".isPrefixOf( re ); // true
"x".isPrefixOf( re ); // false
isPrefixOf
的实现怎么样?
更新:感谢您的回答,正如brad所建议的那样,使正则表达式前缀保证似乎是一个很好的解决方法。但我仍在努力寻找一般解决方案。
也许这样:我们使用用户输入后跟.*
创建一个新的正则表达式。此正则表达式描述了用户仍可输入的所有单词。如果此创建的正则表达式与原始正则表达式的交集为空,则表示用户已经错误。如果不是,他表现得很好。例如:
var re = /a*b/;
var sInput = "a";
var reInput = new RegExp( sInput + ".*" );
reIntersection = re.intersect( reInput );
reIntersection.isEmpty(); // false
intersect()
会返回一个新的正则表达式,只接受re
和reInput
都接受的单词。该功能尚不存在,但我们可以使用预见来实现它:
RegExp.prototype.intersect = function( pattern2 ) {
return new RegExp( '(?=' + this.source + ')' + pattern2.source );
}
剩下的是isEmpty()
功能。如果Javascript正则表达式匹配任何单词或者它是否为空,我们如何检查?
答案 0 :(得分:4)
人们似乎在分析他们如何解释这个问题,所以我将用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()
方法那样的东西,但它可能会伪造它。如果有人知道怎么做,那就是Flagrant Badass,Steven Levithan。
答案 1 :(得分:3)
我认为你最好的选择是让你的正则表达式前缀。对于您提供的示例/a*b/
,我认为您可以使用/a*b?/.test(userinput)
。对于更复杂的模式,这可能变得越来越困难,但我仍然认为可以通过将每个子表达式嵌套在一系列可选的量词(?
)中来完成。例如:
/a*bcd*e/
前缀正则表达式可以是:
/a*(b(c(d*e?)?)?)?/
它有点乱,但我认为会很好地解决你的问题。
答案 2 :(得分:2)
非常有趣的问题。在我的快速搜索中,我没有找到任何预定义的(甚至在Perl中都没有)来解决这个问题。
编辑:哎呀,似乎Java有类似的东西叫做hitEnd() - 看看Alan M的回答。 hitEnd()的作用是说match()的结果(true或false)可能会被附加输入修改。 “Mastering Regular Expressions”这本书说它不太可靠(不确定为什么,第392页没有谷歌书籍)。根据您使用的正则表达式的哪些功能,快速破解,例如编写正则表达式的某些前缀:
e.g。对于a + 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无法处理反向引用))。
答案 3 :(得分:-1)
首先,将正则表达式定义为: var re = new RegExp(/ ^(regexp here)$ /);
在onKeypress事件上,你可以像这样检查正则表达式:
text.match(regexp) - 文本是输入的字符串。
这是清楚的吗?
答案 4 :(得分:-1)
这样做的一种方法是挂钩文本框的onKeyUp事件,并将 .test 挂接到正则表达式。 我的假设当然是你想要进行正则表达式匹配。 我不确定这是否正是您所需要的,实际上是您的代码:
"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>