您似乎正在尝试捕获 RHS 字符串的内容,同时强制它前面是 "body":",后面是 "。
您似乎在使用环视断言来测试周围文本是否存在,但您也在使用捕获组来捕获 RHS 字符串的内容。你不需要做这两件事。环顾断言是零宽度,这意味着它们不会构成最终匹配子字符串的一部分。最终匹配的子字符串始终可以作为捕获组 0 访问。或者,您可以完全匹配所有正则表达式组件(意味着非零宽度匹配,意味着没有环视)并使用捕获组来提取感兴趣的子字符串,但这将是效率较低。
这是我认为应该这样写的(与此演示的 args[0] 匹配):
Pattern p = Pattern.compile("(?<=\"body\":\")[^\"]*(?=\")");
Matcher m = p.matcher(args[0]);
if (!m.find(0)) { System.out.println("doesn't match!"); System.exit(1); }
System.out.println(m.group(0));
以上对我来说适用于相当大的字符串。
我确实尝试重现 StackOverflowError 异常,并且成功了。在我看来,Java 正则表达式引擎正在使用递归来实现重复交替的匹配。这对我来说非常令人惊讶,因为我不知道为什么需要递归来匹配重复的交替。话虽如此,我还对 Perl 正则表达式进行了一些测试,我一直认为它是现存最强大和最健壮的正则表达式风格,我更惊讶地发现 Perl 的失败方式与 Java 完全相同正则表达式。
下面是一个例子,显示了 Java 失败和 Perl 失败。对于这个演示,我将[^"] 原子更改为替换(?:\\.|[^"]),它有效地添加了对嵌入双引号字符串中的反斜杠转义码的支持,例如\" 来编码嵌入的双引号,这通常是受支持的在许多编程环境中。
Java
Pattern p = Pattern.compile("(?<=\"body\":\")(?:\\\\.|[^\"])*(?=\")");
Matcher m = p.matcher(args[0]);
if (!m.find(0)) { System.out.println("doesn't match!"); System.exit(1); }
System.out.println(m.group(0));
输出
Exception in thread "main" java.lang.StackOverflowError
at java.util.regex.Pattern$CharProperty.match(Unknown Source)
at java.util.regex.Pattern$Branch.match(Unknown Source)
at java.util.regex.Pattern$GroupHead.match(Unknown Source)
at java.util.regex.Pattern$Loop.match(Unknown Source)
at java.util.regex.Pattern$GroupTail.match(Unknown Source)
at java.util.regex.Pattern$BranchConn.match(Unknown Source)
at java.util.regex.Pattern$CharProperty.match(Unknown Source)
at java.util.regex.Pattern$Branch.match(Unknown Source)
at java.util.regex.Pattern$GroupHead.match(Unknown Source)
at java.util.regex.Pattern$Loop.match(Unknown Source)
at java.util.regex.Pattern$GroupTail.match(Unknown Source)
...
Perl(来自 shell)
largeString="\"body\":\"$(perl -e 'use strict; use warnings; for (my $i = 0; $i < 2**15; ++$i) { print("x"); }';)\"";
perl -e 'use strict; use warnings; my $re = qr((?<="body":")(?:\\.|[^"])*(?=")); if ($ARGV[0] !~ $re) { print("didn'\''t match!\n"); } print($&);' "$largeString";
输出
Complex regular subexpression recursion limit (32766) exceeded at -e line 1.
didn't match!
Use of uninitialized value $& in print at -e line 1.
所以,为了澄清一下,我在答案开头附近给出的解决方案避免此堆栈溢出错误的原因不是因为我删除了捕获组 1,而是因为我删除了交替。同样,我不知道为什么使用递归来实现重复交替,但鉴于这一事实,大输入字符串会导致堆栈溢出错误似乎是合乎逻辑的。