匹配器输入中的Java正则表达式

时间:2013-11-19 21:45:28

标签: java regex matcher

我正在尝试使用regexp获取引用的字符串。

String regexp = "('([^\\\\']+|\\\\([btnfr\"'\\\\]|[0-3]?[0-7]{1,2}|u[0-9a-fA-F]{4}))*'|\"([^\\\\\"]+|\\\\([btnfr\"'\\\\]|[0-3]?[0-7]{1,2}|u[0-9a-fA-F]{4}))*\")";
Pattern p = Pattern.compile(regexp);
Matcher m = p.matcher(source); 
while (m.find()) {
    String newElement = m.group(1);
    //...
}

效果很好,但如果源文本包含

' onkeyup="this.value = this.value.replace (/\D/, \'\')">'

程序进入永恒循环。

如何正确获取此字符串?

例如,我有一个文本(php代码):

'qty'=>'<input type="text" maxlength="3" class="qty_text" id='.$key.' value ='

结果应为

'qty'
'<input type="text" maxlength="3" class="qty_text" id='
' value ='

4 个答案:

答案 0 :(得分:0)

也许我误解了这个原则,但是现在你添加了这个例子,这看起来相当微不足道。

例如考虑这个:

String input = "'qty'=>'<input type=\"text\" maxlength=\"3\" class=\"qty_text\" id='.$key.' value ='";
String otherInput = "' onkeyup=\"this.value = this.value.replace (/\\D/, \'\')\">'";
// matching anything starting with single quote and ending with single quote 
// included, reluctant quantified
Pattern p = Pattern.compile("'.+?'");
Matcher m = p.matcher(input);
while (m.find()) {
    System.out.println(m.group());
}
m = p.matcher(otherInput);
System.out.println();
while (m.find()) {
    System.out.println(m.group());
}

输出:

'qty'
'<input type="text" maxlength="3" class="qty_text" id='
' value ='

' onkeyup="this.value = this.value.replace (/\D/, '
')">'

有关更详细的说明,请参阅Java Pattern documentation

答案 1 :(得分:0)

既不匹配反斜杠也不匹配引号的字符组不应该跟+后跟。删除+以修复挂起(由catastrophic backtracking引起)。

此外,您的原始正则表达式未将\D识别为有效的反斜杠转义符 - 因此,包含\D的测试输入中的字符串常量未匹配。如果你使正则表达式的规则更自由地识别任何字符紧跟在反斜杠后面作为字符串常量的一部分,它将按照你期望的方式运行。

"('([^\\\\']|\\\\.)*'|\"([^\\\\\"]|\\\\.)*\")"

答案 2 :(得分:0)

当你的正则表达式匹配时,你的正则表达式似乎工作正常;当它无法匹配它进入无限循环时。 (在这种情况下,导致它窒息的是\D。)但是正则表达式要比它需要的复杂得多;你正试图匹配他们,而不是验证他们。这是C风格语言中字符串文字的典型正则表达式:

"[^"\\\r\n]*(?:\\.[^"\\\r\n]*)*"

...和单引号版本,支持该样式的语言:

'[^'\\\r\n]*(?:\\.[^'\\\r\n]*)*'

它使用Friedl的“展开循环”技术以实现最高效率。这是由RegexBuddy 4生成的Java代码:

Pattern regex = Pattern.compile(
    "\"[^\"\\\\\r\n]*(?:\\\\.[^\"\\\\\r\n]*)*\"|'[^'\\\\\r\n]*(?:\\\\.[^'\\\\\r\n]*)*'"
);

答案 3 :(得分:0)

您可以使用正确的正则表达式split()在一行中完成所有操作:

String[] array = source.replaceAll("^[^']+", "").split("(?<!\\G.)(?<=').*?(?='|$)");

这里有合理数量的正则表达式功夫,所以我会将其分解:

  • 分隔符用偶数/奇数引号括起来,但不能包含引号,因为split() 消耗分隔符,所以看看{{1并且向前看(?<=')(非消耗的)用于匹配引号而不是正则表达式中的文字引用
  • 引号之间字符的不情愿匹配(?=')确保它在下一个引号处停止(而不是匹配到最后一个引号)
  • 我为输入结尾添加了一个替代匹配,他向前看.*?,以防没有尾随报价
  • 并且为最后一次保存最好的,使这一切成为关键的正则表达式是(?='|$)背后的负面看法,这意味着“在上一场比赛结束时不匹配”并确保下一场比赛超过前一个分隔符的末尾,没有它,你最终只会得到数组中的引号字符。 (?<!\\G.)与上一场比赛的 end 相匹配,但也匹配第一场比赛的输入开头,因此它会在第一场比赛中自动处理 not 匹配 - 因此使分隔符包含在偶数/奇数引号中,而不是奇数/偶数,否则就是这样。
  • 为了满足输入的第一个不是引号的字符,你需要在分割之前去除主要字符 - 这就是为什么需要\G

以下是使用示例输入的一些测试代码:

replaceAll()

输出:

String source = "'qty'=>'<input type=\"text\" maxlength=\"3\" class=\"qty_text\" id='.$key.' value ='";
String[] array = source.replaceAll("^[^']+", "").split("(?<!\\G.)(?<=').*?(?='|$)");
System.out.println(Arrays.toString(array));