在Java代码中优化几个RegEx

时间:2011-11-24 08:18:30

标签: java regex optimization

下面提到的RegEx在非常大的字符串或超过2000行上表现非常差。基本上Java String由PL / SQL脚本组成。

1-替换每次出现的分隔符,例如||,!=或>在角色之前和之后用空格签名。这需要无限的时间,永远不会结束,所以没有时间记录。

// Delimiting characters for SQLPlus
private static final String[] delimiters = { "\\|\\|", "=>", ":=", "!=", "<>", "<", ">", "\\(", "\\)", "!", ",", "\\+", "-", "=", "\\*", "\\|" };


for (int i = 0; i < delimiters.length; i++) {
    script = script.replaceAll(delimiters[i], " " + delimiters[i] + " ");
}

2-以下模式查找正斜杠的所有出现/除前面带*的斜杠。这意味着不要在块注释语法中寻找正斜杠。对于2000行字符串,这需要大约103秒。

Pattern p = Pattern.compile("([^\\*])([\\/])([^\\*])");
Matcher m = p.matcher(script);
while (m.find()) {
    script = script.replaceAll(m.group(2), " " + m.group(2) + " ");
}

3-从日期或日期格式中删除任何空格

Pattern p = Pattern.compile("(?i)(\\w{1,2}) +/ +(\\w{1,2}) +/ +(\\w{2,4})");
// Create a matcher with an input string
Matcher m = p.matcher(script);
while (m.find()) {
    part1 = script.substring(0, m.start());
    part2 = script.substring(m.end());
    script = part1 + m.group().replaceAll("[ \t]+", "") + part2;
    m = p.matcher(script);
}

有没有办法优化所有三个RegEx,以便缩短时间?

由于

阿里

3 个答案:

答案 0 :(得分:2)

我将回答第一个问题。

您可以将所有这些组合到一个正则表达式替换操作中:

script = script.replaceAll("\\|\\||=>|[:!]=|<>|[<>()!,+=*|-]", " $0 ");

<强>解释

\|\|            # Match ||
|               # or
=>              # =>
|               # or
[:!]=           # := or !=
|               # or
<>              # <>
|               # or
[<>()!,+=*|-]   # <, >, (, ), !, comma, +, =, *, | or -

答案 1 :(得分:1)

不确定。你的第二种方法“差不多”好。问题是您不使用您的模式进行替换。当您使用str.replaceAll()时,每次调用此方法时实际创建Pattern实例。 Pattern.compile()被称为你,需要90%的时间。

您应该使用Matcher.replaceAll()代替。

    String script = "dfgafjd;fjfd;jfd;djf;jds\\fdfdf****\\/";
    String result = script;

    Pattern p = Pattern.compile("[\\*\\/\\\\]"); // write all characters you want to remove here.
    Matcher m = p.matcher(script);
    if (m.find()) {
        result = m.replaceAll("");
    }       
    System.out.println(result);

答案 2 :(得分:1)

这不是导致性能问题的正则表达式,而是您正在对文本进行多次传递,并不断创建新的Pattern对象。蒂姆指出,这不仅仅是表现受到影响;当你这样做时,很容易弄乱先前通行证的结果。

事实上,我猜测日期中的那些额外空间只是你的其他替代品的副作用。如果是这样,这里有一种方法可以在一次通过中完成所有替换,而无需添加不需要的字符:

static String doReplace(String input)
{
  String regex = 
      "/\\*[^*]*(?:\\*(?!/)[^*]*)*\\*/|"      // a comment
    + "\\b\\d{2}/\\d{2}/\\d{2,4}\\b|"         // a date
    + "(/|\\|\\||=>|[:!]=|<>|[<>()!,+=*|-])"; // an operator

  Matcher m = Pattern.compile(regex).matcher(input);
  StringBuffer sb = new StringBuffer();
  while (m.find())
  {
     // if we found an operator, replace it
    if (m.start(1) != -1)
    {
      m.appendReplacement(sb, " $1 ");
    }
  }
  m.appendTail(sb);
  return sb.toString();
}

<强> see the online demo

诀窍是,如果你不打电话appendReplacement(),匹配位置不会更新,所以就好像没有发生匹配一样。因为我忽略它们,所以注释和日期会与其他不匹配的文本一起重新插入,而且我不必担心匹配它们内部的斜杠字符。

编辑确保正则表达式的“注释”部分位于“运算符”部分之前。否则,每条评论的前导/将被视为操作员。