Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/18.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 Pattern.matches()给出StackOverflowerError_Java_Regex_Stack Overflow - Fatal编程技术网

Java Pattern.matches()给出StackOverflowerError

Java Pattern.matches()给出StackOverflowerError,java,regex,stack-overflow,Java,Regex,Stack Overflow,我使用java的Pattern.matches将一个数据块与一个正则表达式相匹配。数据块可以是单行或多行。问题是,一旦我的数据超过15行(通常超过17-18行),我就开始得到StackOverflowerError。对于小于15行的数据,正则表达式可以正常工作 正则表达式的格式如下: 域名->空格->,->空格->数字->空格->,->空格->数字->换行符 String regex = "^(([a-zA-Z0-9][a-zA-Z0-9\\-]*\\.)+([a-zA-Z]{2,})\\s*,

我使用java的Pattern.matches将一个数据块与一个正则表达式相匹配。数据块可以是单行或多行。问题是,一旦我的数据超过15行(通常超过17-18行),我就开始得到StackOverflowerError。对于小于15行的数据,正则表达式可以正常工作

正则表达式的格式如下:
域名->空格->,->空格->数字->空格->,->空格->数字->换行符

String regex = "^(([a-zA-Z0-9][a-zA-Z0-9\\-]*\\.)+([a-zA-Z]{2,})\\s*,\\s*\\d+\\s*,\\s*\\d+(\\r?\\n)?)+$";
我用来测试这个正则表达式的数据块是

abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
abc.com, 123, 456
这是代码:

String regex = "^(([a-zA-Z0-9][a-zA-Z0-9\\-]*\\.)+([a-zA-Z]{2,})\\s*,\\s*\\d+\\s*,\\s*\\d+(\\r?\\n)?)+$";
boolean valid = Pattern.matches(regex, data); //fails here

我不能告诉你这个错误的原因;正则表达式本身很好,不会出现灾难性的回溯或任何其他明显的错误

也许您可以通过使用(
++
而不是
++
*++
而不是
*
{2,}+
而不是
{2,}
等)来减少正则表达式引擎保存的回溯位置的数量。此外,您不需要捕获组(感谢Thomas),因此我将它们更改为非捕获组:

"(?:(?:[a-zA-Z0-9][a-zA-Z0-9-]*+\\.)++([a-zA-Z]{2,}+)\\s*+,\\s*+\\d++\\s*+,\\s*+\\d++(\r?+\n)?+)++"

这不会改变正则表达式的行为(除了使用
Pattern.matches()
删除不必要的锚之外),但可能有助于避免堆栈溢出。我没有安装Java SDK,所以我不能自己测试它。

我重现了这个问题,但只针对更大的字符串

$ java -version
java version "1.6.0_22"
OpenJDK Runtime Environment (IcedTea6 1.10.2)    (6b22-1.10.2-0ubuntu1~11.04.1)
OpenJDK 64-Bit Server VM (build 20.0-b11, mixed mode)
我的测试代码:

public class Testje
{
    public static void main(String... args)
    {
        String regex = "^(([a-zA-Z0-9][a-zA-Z0-9\\-]*\\.)+([a-zA-Z]{2,})\\s*,\\s*\\d+\\s*,\\s*\\d+(\\r?\\n)?)+$";
        String data = "";
        for (int i = 0; i<224; i++) data += "abc.com, 123, 456\n";
        System.out.println(data.matches(regex));
    }
}
公共类Testje
{
公共静态void main(字符串…参数)
{
String regex=“^([a-zA-Z0-9][a-zA-Z0-9\\-]*\\)+([a-zA-Z]{2,})\\s*,\\s*\\d+\\s*,\\s*\\d+(\\r?\\n)?)+$”;
字符串数据=”;

对于(int i=0;i您可以尝试使用原子组(
(?>表达式)
)来防止回溯:

这里有一个测试,使用您的正则表达式测试了1000行,但失败了,但现在成功了(需要一段时间,因此我只测试了5000 20000:):

String regex=“(?>(?>[a-zA-Z0-9][a-zA-Z0-9\\-]*\\)+(?>[a-zA-Z]{2,})\\s*,\\s*\\d+\\s*,\\s*\\d+(?>\\r?\\n)?+”;
StringBuilder输入=新建StringBuilder();
对于(int i=0;i<1000000;++i){
input.append(“abc.com,123456\n”);
}
Pattern p=Pattern.compile(regex);
匹配器m=p.Matcher(输入);
System.out.println(m.matches());
因此,毕竟,这可能仍然是一个回溯问题

更新:只需让该测试运行20000行,仍然没有失败。这至少是以前的20倍。:)


更新2:再次查看我的测试,我发现了缓慢的部分,字符串连接。(o..o)。我更新了测试并使用了100万行,仍然没有失败。

问题是您的正则表达式太复杂。您处理的每一行输入都会产生(我想)10个回溯点,其中至少有一部分似乎是由正则表达式引擎递归处理的。这可能是几百个堆栈帧,足以给您提供
StackOverflowerError

在我看来,您需要修改模式,使其匹配一组/行数据。然后调用
Matcher。反复查找
,以解析每行数据。我希望您会发现这样做更快


以其他方式优化正则表达式,同时仍尝试一次性匹配整个块可能不起作用。您可能可以使其匹配N倍多的数据行,但随着输入中行数的增加,您可能会再次遇到相同的问题

即使您确实让它作为多行正则表达式工作,它也有可能无法与Java正则表达式库的其他实现一起工作;例如,在较旧的Oracle JRE或非Oracle实现中



我同意其他答案,即这不是“灾难性回溯”的例子。相反,这是正则表达式引擎处理回溯点的方式与这样一个事实之间的相互作用,即当你给它多行输入时,回溯点太多了。

+1在野外实际遇到这个同名错误。:)提示1)你不必逃避
-
这里:
[a-zA-Z0-9\\\-]
(即:
a-zA-Z-]
)有效2)使用
时不需要使用
^
$
。matches()
您需要组还是非捕获组也可以工作?如果需要,请将
替换为
(?:
@Thomas:No,未转义的
-
在字符类的第一个或最后一个位置总是明确无误的。我不知道有哪一个正则表达式风格会以任何其他方式处理它。@Thomas我更喜欢它,因为它更具可读性,特别是当涉及到需要双转义的Java正则表达式时。我使用了你的正则表达式,它几乎翻了一倍该错误的行数(现在大约清除了30行)。但在这之后,我仍然得到相同的错误:(@NullUserException)ఠ_ఠ: 你说得对,我们需要看一些代码。然而,我对Xion的评论很感兴趣,他说正则表达式引擎可能存在已知问题。那么,如果不在堆栈上,回溯位置存储在哪里?如果你更改最后的
+
(在正则表达式的末尾)是否有任何变化为了
++
?@Tim在我的测试结束时(见下文),我用
++
替换了
++
,它解析了一百万行,所以你的解决方案是干扰最小的一个-只需多一个字符(如果你保持捕获组的话)(+1):)就很有趣了。只是为了刺激一下,
”(?:(?:[a-zA-Z0-9][a-zA-Z0-9-]*\\\+([a-zA-Z]{2,})\\s*,\\s*\\d++\\s*,\\s*\\d++(\r?\n)?++“
(只是最后的所有格量词)?您的正则表达式允许我清除多达200行数据(这是我需要的最大值)…但我仍然不明白问题是什么:(@Purav:我不确定,但可能确实很有趣,可以处理20000行,但在200行时失败。@NullUserExceptionఠ_ఠ 当然,这取决于正则表达式引擎,但是Java在失败之前也可以处理更多(基于J
String regex = "(?>(?>[a-zA-Z0-9][a-zA-Z0-9\\-]*\\.)+(?>[a-zA-Z]{2,})\\s*,\\s*\\d+\\s*,\\s*\\d+(?>\\r?\\n)?)+";

StringBuilder input = new StringBuilder();

for( int i = 0; i < 1000000; ++i) {
  input.append("abc.com, 123, 456\n");
}

Pattern p = Pattern.compile( regex );
Matcher m = p.matcher( input );

System.out.println(m.matches());