【问题标题】:Fastest way to perform a lot of strings replace in Java在 Java 中执行大量字符串替换的最快方法
【发布时间】:2011-05-16 03:58:51
【问题描述】:

我必须编写某种解析器来获取字符串并将某些字符集替换为其他字符集。代码如下所示:

noHTMLString = noHTMLString.replaceAll("</p>", "\n");
noHTMLString = noHTMLString.replaceAll("<br/>", "\n\n");
noHTMLString = noHTMLString.replaceAll("<br />", "\n\n");
//here goes A LOT of lines like these ones

该函数很长并且执行大量字符串替换。这里的问题是它需要很多时间,因为它被多次调用的方法会降低应用程序的性能。

我在这里阅读了一些关于使用 StringBuilder 作为替代方法的主题,但它缺少 ReplaceAll 方法,正如这里提到的 Does string.replaceAll() performance suffer from string immutability? String 类中的 replaceAll 方法适用于

Match Pattern & Matcher 和 Matcher.replaceAll() 使用 StringBuilder 来存储最终返回的值 所以我不知道切换到 StringBuilder 是否真的会减少执行替换的时间。

您知道快速进行大量字符串替换的快速方法吗?您对这个问题有什么建议吗?

谢谢。

编辑:我必须创建一个报告,其中包含一些带有 html 文本的字段。对于每一行,我都调用了替换这些字符串中的所有 html 标记和特殊字符的方法。使用完整的报告,解析所有文本需要 3 分钟以上。问题是我必须经常调用该方法

【问题讨论】:

  • 是什么让你慢了下来? - 你的 noHTMLString 文本的长度,或者你是否经常调用这三个语句?
  • 我必须创建一个报告,其中包含一些带有 html 文本的字段。对于每一行,我都调用了替换这些字符串中的所有 html 标记和特殊字符的方法。使用完整的报告,解析所有文本需要 3 分钟以上。所以我的问题是我必须经常调用该方法。

标签: java regex string


【解决方案1】:

我发现 org.apache.commons.lang.StringUtils 是最快的,如果你不想打扰 StringBuffer 的话。

你可以这样使用它:
noHTMLString = StringUtils.replace(noHTMLString, "&lt;/p&gt;", "\n");

我进行了性能测试,它比我的自定义 StrinBuffer 解决方案更糟糕,类似于@extraneon 提出的解决方案。

【讨论】:

【解决方案2】:

我同意 Martijn 的观点,即使用现成的解决方案而不是自己解析它 - 在 javax.xml 包中 Java 内置了很多东西。一个巧妙的解决方案是使用 XSLT 转换来替换,这看起来像是一个理想的用例。但是,这很复杂。

要回答这个问题,您是否考虑过使用regular expression libraries?看起来你有很多不同的东西要匹配,并用相同的东西(\n 或空字符串)替换。使用正则表达式,您可以像 "&lt;br&gt;|&lt;br/&gt;|&lt;br /&gt;" 这样的表达式,或者更聪明的像 &lt;br.*?&gt;" 这样的表达式来创建一个匹配器对象,您可以在该对象上调用 replaceAll。

【讨论】:

  • 不能用正则表达式解析 HTML:stackoverflow.com/questions/1732348/…
  • Adriaan,你是对的,HTML 是一种上下文无关语言,而不是常规语言。但是您可以使用正则表达式进行文本替换,这就是我们所要求的。
【解决方案3】:

我完全同意 Martijn 的观点。为工作选择合适的工具。

如果您的文件不是 HTML,但仅包含一些 HTML 标记,则有几种方法可以加快处理速度。

首先,如果某些输入不包含可替换元素,请考虑从以下内容开始:

if (!input.contains('<')) {
    return input;
}

其次,考虑一个正则表达式:

Pattern p = Pattern.compile( your_regex );

不要为每一个 replaceAll 行创建一个模式,而是尝试将它们组合起来(正则表达式有一个 OR 运算符)并让 Pattern 优化正则表达式。一定要使用 compiled 模式,不要在每次调用时都编译它,它相当昂贵。

如果正则表达式有点复杂,您也可以自己实现一些更快(但可能不太可读)的替换引擎:

StringBuilder result = new StringBuilder(input.length();
for (int i=0; i < input.length(); i++) {
  char c = input.charAt(i);

  if ( c != '<' ) {
    continue;
  }

  int closePos = input.indexOf( '>', i);
  if (closePos == -1) {// not found
    result.append( input.substring(i, input.length());
    return result.toString();
  }
  i = closePos;
  String token = input.substring(i, closePos);
  if ( token.equals( "p/" ) {
    result.append("\\n");
  } else if (token.equals(...)) {
  } else if (...) {
  } 
}
return result.toString();

这可能有一些错误:)

优点是您只需遍历输入一次。最大的缺点是它不是那么容易理解。您还可以编写一个状态机,分析每个字符的新状态应该是什么,这可能会更快,甚至更多的工作。

【讨论】:

  • 不能用正则表达式解析 HTML:stackoverflow.com/questions/1732348/…
  • @Adriaan Koster:我不是这么说的。我说,如果您有 HTML,请使用 HTML 解析器。如果它是带有 HTML 标记的纯文本(HTML 解析器无法解析),请尝试一下。
  • @Adriaan:错了! Yes you can parse HTML with regex。但是,您 probably don’t want to 除非您使用的 HTML 受到约束和限制,例如您自己生成的。否则虽然用正则表达式解析 HTML 是完全可能的,但你真的不想这样做。
  • 迟来的挑剔:你不能用 single 正则表达式解析任意 HTML,因为正则表达式无法识别任意深度的递归嵌套。您当然可以使用一个或多个正则表达式对任意 HTML 执行词法分析(即标记化),就像您可能能够识别 HTML 文件中有趣的部分一样。
【解决方案4】:

看起来你在那里解析 HTML,你有没有想过使用 3rd party library 而不是重新发明轮子?

【讨论】:

    猜你喜欢
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    • 2013-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多