Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/386.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有趣的Java正则表达式限制_Java_Python_Regex_Backtracking - Fatal编程技术网

有趣的Java正则表达式限制

有趣的Java正则表达式限制,java,python,regex,backtracking,Java,Python,Regex,Backtracking,我曾在Python中尝试过相同的表达式,但在这里似乎没有问题,而Java由于堆栈溢出而失败 这是演示问题的简化测试用例: // 10k whitespace. char[] buf = new char[10000]; Arrays.fill(buf, ' '); String post = new String(buf); // All whitespace - works System.out.println(Pattern.compile(" +").matcher(post).match

我曾在Python中尝试过相同的表达式,但在这里似乎没有问题,而Java由于堆栈溢出而失败

这是演示问题的简化测试用例:

// 10k whitespace.
char[] buf = new char[10000];
Arrays.fill(buf, ' ');
String post = new String(buf);
// All whitespace - works
System.out.println(Pattern.compile(" +").matcher(post).matches());
// All whitespace, or whitespace - Stack Overflow
System.out.println(Pattern.compile("(?: | )+").matcher(post).matches());
第一个正则表达式,
“+”
工作正常。第二个字符串,
“(|)+”
——显然也应该匹配此字符串,但是会导致堆栈溢出

我想这是一个限制,因为正则表达式(特别是:替代)是在Java中实现的。。。基于状态机的regexp匹配器似乎还可以(它们将保持在接受状态);或者pythons regexp引擎只是有一个更大的堆栈

通过原子组禁用回溯也有效:
“(?>)+”
-我猜在这种情况下,Java将不再在每个匹配上添加6个堆栈帧(显然,默认情况下,堆栈无法容纳60000帧)

这不仅仅是一个理论上的例子。考虑例如“代码>”(苹果香蕉)+“< /代码>:

StringBuilder buf=new StringBuilder();
对于(int i=0;i<10000;i++)
buf.append(Math.random()<.5?“苹果”:“香蕉”);
字符串s=buf.toString();
System.out.println(s.replaceAll(“(苹果香蕉)+”,“很多水果”);
使用
“(?>苹果|香蕉)+”
它将根据需要打印大量水果
;如果没有回溯预防,将导致堆栈溢出

是的,我知道这是一种灾难性的回溯。。。令我惊讶的是Java很早就失败了,Python仍然兴高采烈地运行着,成功地删除了不需要的文本。。。python是否更聪明,并且认识到它可以“贪婪”地处理而无需回溯?还是它只是更好地利用了内存?

(|)+
是一个非常基本的例子。在这种情况下,最好称之为灾难性分支,因为不涉及回溯

似乎Java可以使用递归实现分支,尽管我不确定10000级的深度是否足以触发溢出。也有可能它试图深入2^10000层,但由于我对内部一无所知,这纯粹是猜测更新:您说过1000不足以溢出,所以它看起来绝对是线性的,而不是指数的

你为什么不试着缩短你的字符串,看看它到底需要多长时间才能溢出呢?另外,试试类似的
(苹果香蕉)+
,看看它是否也有同样的问题更新:任何分支方案都可能出现问题。这肯定是Java正则表达式引擎中的一个弱点,尽管我不能确切地告诉您原因。除了Python之外,我可以确认它在.NET和JavaScript(不管怎样,我的浏览器)中工作良好


我不认为这是NFA驱动发动机的问题。我假设Java使用了另一种方法,但我找不到任何地方有记录在案。

如果你有一个更小的
字符串怎么办?如果你使用:
char[]buf=new char[1000]?只要1000,堆栈就不会溢出。;-)这是我的看法,它试图使用Java堆栈跟踪。每个分支需要6个堆栈帧。。。我最初的案例更多的是苹果香蕉案。灾难性的回溯通常是在负面匹配上。。。这是您在这种模式中不希望看到的(它最初是一个替代调用,删除了一些替代项;使用
+
将多个匹配项合并为一个)。当您使用apple banana正则表达式时,它是否也会溢出?显然,它在第一个字符处不匹配。但是如果你愿意,你可以建立一个包含苹果和香蕉的缓冲区。@anonymouse,如果你这样做会发生什么?我不写Java,所以现在无法测试它。
StringBuilder buf = new StringBuilder();
for (int i = 0; i < 10000; i++)
    buf.append(Math.random() < .5 ? "apple" : "banana");
String s = buf.toString();
System.out.println(s.replaceAll("(apple|banana)+", "lots of fruits"));