我必须编写某种解析器来获取String并用其他字符替换某些字符集。代码如下所示:
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方法与
一起使用匹配模式&amp; Matcher和Matcher.replaceAll()使用StringBuilder存储最终返回的值 所以我不知道切换到StringBuilder是否会真正减少执行替换的时间。
您是否知道以快速方式快速完成大量字符串替换?你对这个问题有什么建议吗?
感谢。
编辑:我必须创建一个包含html文本字段的报表。对于每一行,我正在调用替换这些字符串中的所有html标记和特殊字符的方法。使用完整报告,解析所有文本需要3分钟以上。问题是我必须经常调用该方法
答案 0 :(得分:12)
如果你不想打扰StringBuffer,我发现org.apache.commons.lang.StringUtils是最快的。
您可以这样使用它:
noHTMLString = StringUtils.replace(noHTMLString, "</p>", "\n");
我做了性能测试,它比我自定义的StrinBuffer解决方案更糟糕,类似于@extraneon提出的解决方案。
答案 1 :(得分:6)
看起来你在那里解析HTML,你有没有使用3rd party library而不是重新发明轮子?
答案 2 :(得分:4)
我同意Martijn使用现成的解决方案而不是自己解析它 - 在javax.xml包中有很多内置于Java中的东西。一个简洁的解决方案是使用XSLT转换来替换,这看起来像是一个理想的用例。但是,它很复杂。
要回答这个问题,您是否考虑过使用regular expression libraries?看起来你想要匹配许多不同的东西,并用相同的东西(\ n或空字符串)替换。使用正则表达式,您可以使用"<br>|<br/>|<br />"
之类的表达式,或者更像<br.*?>"
这样的聪明表达式来创建匹配器对象,您可以在其上调用replaceAll。
答案 3 :(得分:3)
我完全同意Martijn的观点。为工作选择合适的工具。
如果您的文件不是HTML,但只包含一些HTML令牌,则有几种方法可以加快速度。
首先,如果某些输入量不包含可替换元素,请考虑从以下内容开始:
if (!input.contains('<')) {
return input;
}
其次,考虑正则表达式:
Pattern p = Pattern.compile( your_regex );
不要为每一个replaceAll行创建一个模式,而是尝试将它们组合在一起(regex有一个OR运算符)并让Pattern优化正则表达式。使用编译的模式并且不在每次调用中编译它,它相当昂贵。
如果regex有点复杂,你也可以自己实现一些更快(但可能不太可读)的替换引擎:
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();
这可能有一些错误:)
优点是你必须只迭代输入一次。最大的缺点是它并不容易理解。你也可以编写一个状态机,分析每个字符应该是什么新状态,这可能会更快,甚至更多的工作。