在替换之前检查字符串是否包含子字符串是否值得?

时间:2016-12-19 11:34:55

标签: java string replace

我今天看到了这段代码

if (translatedText.contains("â")) translatedText = translatedText.replace("â", "a");
if (translatedText.contains("ê")) translatedText = translatedText.replace("ê", "e");
...

有22条这样的线,我想知道在替换之前使用“ifs”有什么意义。我理解它的方式是有效的,我们每行读取两次字符串,而当没有什么可以替换的时候直接调用replace方法会产生相同的效果,当有什么要替换时会更快。

但这只是我猜它的运作方式。有人可以确认或纠正我吗?

还有第二个问题。我们正在替换每个元音和每个符号“á”,“à”,“â”和“ä”。我敢打赌,在Java中有更好的方法。有什么建议吗?

感谢。

4 个答案:

答案 0 :(得分:7)

documentation并没有告诉我们replace如果没有匹配的子字符串会做什么,但是查看Oracle版本中的当前实现(Java 8) ):

public String replace(CharSequence target, CharSequence replacement) {
    return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
            this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
}

...如果你先检查一下,它看起来就像你避免了一些工作,特别是内存分配(匹配器)。

并不是说不可能有更好的方法来接近这22个替换,可能是通过使用一个带有字符类([âê]等的正则表达式),编译一次正则表达式,然后在循环中使用单个匹配器,非常大致相似(灵感来自this answer):

// You can do this part once somewhere if you want to
Pattern regex = Pattern.compile("[âê]");
// Then:
StringBuffer resultString = new StringBuffer();
Matcher regexMatcher = regex.matcher(translatedText);
while (regexMatcher.find()) {
    String match = regexMatch.group();
    String replacement;
    switch (match) {
        // ...various cases setting `replacement`
    }
    regexMatcher.appendReplacement(resultString, replacement);
}
regexMatcher.appendTail(resultString);
translatedText = resultString.toString();

或者如果你想过早地对其进行微观优化(我的失败):

// You can do this part once somewhere if you want to
Pattern regex = Pattern.compile("[âê]");
// Then:
StringBuffer resultString = null;
Matcher regexMatcher = regex.matcher(translatedText);
while (regexMatcher.find()) {
    if (resultString == null) {
        resultString = new StringBuffer(translatedText.length() + 100);
    }
    String match = regexMatch.group();
    String replacement;
    switch (match) {
        // ...various cases setting `replacement`
    }
    regexMatcher.appendReplacement(resultString, replacement);
}
if (resultString != null) {
    regexMatcher.appendTail(resultString);
    translatedText = resultString.toString();
}

答案 1 :(得分:3)

关于"性能":这可能真的取决于JVM版本;换句话说:取决于replace()更改的实现,如果到位可以节省一些正则表达式匹配器成本;或不。

关于第二个问题:基本上你有很多重复的代码。解决这个问题的一种方法:

您可以定义一些静态最终字段,例如:

Map<String, String> replacements = new HashMap<>();

然后填写:

replacements.put("â", "a");
...

然后使用循环来替换当前代码,该循环迭代该映射的条目,使用每个键/值作为replace()调用的参数。

或者,如其他答案所示,您可以执行类似

的操作
replacements.put("[áàâä]", "a");

然后再使用replaceAll()。

答案 2 :(得分:2)

您可以使用正则表达式将所有不需要的字符替换为您的字符

String s="sasaáàdaâadsasä";
System.out.println(s.replaceAll("[áàâä]", "a"));

输出

sasaaadaaadsasa

[]表示匹配此中任何出现的字符,如果找到则替换

要替换多个字符,您可以将替换呼叫链接起来,只需避免if条件

String s="sasaáàdaâadsêêêasä";
String str=s.replaceAll("[áàâä]", "a").replaceAll("[ê]", "e");
System.out.println(str);

<强>输出:

sasaaadaaadseeeasa

答案 3 :(得分:2)

如果您希望摆脱明显多余的if语句而不会导致性能下降,那么快速解决方案是切换到使用replace(char, char)

translatedText = translatedText.replace('â', 'a');
translatedText = translatedText.replace('ê', 'e');

这完全避免了正则表达式,无论是显式的还是隐藏的,并且在我的Java 8中也避免了在没有替换的情况下创建新的String

是否有更好的方法取决于几个因素,包括味道。其他几个答案都有很好的想法。