Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/20.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_Regex - Fatal编程技术网

Java中长字符串的正则表达式模式匹配性能

Java中长字符串的正则表达式模式匹配性能,java,regex,Java,Regex,我有一个正则表达式,它在找到匹配项时工作得很好(500纳秒),但在没有匹配项时需要很多时间(超过3秒)。我怀疑这可能是因为回溯。我尝试了一些选项,比如根据一些文档将*转换为(.*),但没有帮助 输入:非常长的字符串-在某些情况下为5k字符 要匹配的正则表达式:*substring1.*substring2. 我正在预编译模式并重新使用matcher,我还可以尝试什么 下面是我的代码片段——我将使用数百万个不同的输入字符串调用此方法,但只使用少数几个正则表达式模式 private static H

我有一个正则表达式,它在找到匹配项时工作得很好(500纳秒),但在没有匹配项时需要很多时间(超过3秒)。我怀疑这可能是因为回溯。我尝试了一些选项,比如根据一些文档将
*
转换为
(.*)
,但没有帮助

输入:非常长的字符串-在某些情况下为5k字符

要匹配的正则表达式:
*substring1.*substring2.

我正在预编译模式并重新使用matcher,我还可以尝试什么

下面是我的代码片段——我将使用数百万个不同的输入字符串调用此方法,但只使用少数几个正则表达式模式

private static HashMap<String, Pattern> patternMap = new HashMap<String, Pattern>();
private static HashMap<String, Matcher> matcherMap = new HashMap<String, Matcher>();
使用
String.indexOf()。您可以将问题重新编码为:

public static boolean containsStrings(String source, String string1, String string2) {
  long pos1, pos2;
  pos1 = source.indexOf(string1);
  if(pos1 > -1) {
    pos2 = source.indexOf(string2,pos1 + string1.length);
    if(pos2 > pos1 && source.indexOf(string1,pos2 + string2.length) < -1) {
      return true;
    }
  }
  return false;
}
public静态布尔值包含字符串(字符串源、字符串string1、字符串string2){
长pos1,pos2;
pos1=source.indexOf(string1);
如果(位置1>-1){
pos2=source.indexOf(string2,pos1+string1.length);
if(pos2>pos1&&source.indexOf(string1,pos2+string2.length)<-1){
返回true;
}
}
返回false;
}

请注意,我的解决方案不处理
string2
包含在
string1
中的情况,如果是这种情况,您需要将其添加到逻辑中。

如果使用
indexOf()
,您可以验证模式是否匹配:


当正则表达式不匹配时,您将得到灾难性的回溯。事实上,您的模式可能会进行很多回溯,即使在有匹配的情况下也是如此。
*
将耗尽整个字符串,然后需要返回,不情愿地返回字符

如果您的字符串看起来像:
substring1 substring2…….50000个字符……
,那么您将使用lazy
*?
获得更好的性能。请注意,
(.*)
*?
不同


正则表达式的性能取决于子字符串是什么以及它们与什么匹配。如果字符串看起来像:
substring1…….50000个字符。。。。。。子字符串2
,则您将使用现有的
*
获得更好的性能。

正如您所暗示的,您的正则表达式存在一个称为灾难性回溯的问题。基本上,第一个
*
将匹配整个字符串,然后回溯到
子字符串1
匹配为止。这将在
子字符串2
中重复。因为
子字符串2
失败,第二个
*
将需要找到另一个
子字符串2
开始匹配的位置,然后它将再次失败。每次
substring1
匹配时,我们都需要检查
substring2
可能匹配的每个位置

您已经在使用
模式.find()
,因此可以省略开头和结尾
*
。然后,将内部的
*
更改为
*?
可以通过将贪婪匹配器变为懒惰匹配器来提高性能

这将生成:
substring1.*?substring2
^((?!substring1)。)*substring1((?!substring2)。*substring2.*\Z


应该这样做,因为一个字符串多次包含一个子字符串,但不是按顺序同时包含两个子字符串,它不会回溯到令人厌恶的地方。如果不需要匹配器在输入结束时结束,则可以将。*?\Z放在末尾。

您的目标是什么?您需要使用正则表达式吗?请出示您的code@Pshemo-是的,我必须使用正则表达式。是否有需要的原因。*前后?如果使用find()而不是match(),并去掉表达式中的.*前缀和后缀,应该会快得多。这些模式是硬编码的还是动态构建的?我可以建议使用展开模式,就像这个想法是好的一样,但是如果出现两次
string2
,一次在
string1
之前,一次在
string1
之后,这将失败。最好先找到
string1
,然后将其索引用作搜索
string2
的开始索引。不幸的是,这不起作用,因为我的函数应该能够处理任何正则表达式。谢谢你的回答。@user100001太糟糕了,在一个有20mb文本的真实案例中,我尽可能多地使用了
indexOf()
contains()
,而regex只用于复杂的案例。在大型文档上节省使用regex的性能提高了几个数量级。完美。这比我的正则表达式表现得更好。谢谢你的回答。
public static boolean containsStrings(String source, String string1, String string2) {
  long pos1, pos2;
  pos1 = source.indexOf(string1);
  if(pos1 > -1) {
    pos2 = source.indexOf(string2,pos1 + string1.length);
    if(pos2 > pos1 && source.indexOf(string1,pos2 + string2.length) < -1) {
      return true;
    }
  }
  return false;
}
int pos1 = str.indexOf("substring1");
int pos2 = str.indexOf("substring2", pos1);

if(pos1 != -1 && pos2 != -1){
  // regex
}