在替换之前检查字符串是不是包含子字符串是不是值得?
Posted
技术标签:
【中文标题】在替换之前检查字符串是不是包含子字符串是不是值得?【英文标题】:Is it worth it to check if a string contains a substring before replacing it?在替换之前检查字符串是否包含子字符串是否值得? 【发布时间】:2017-05-04 10:51:18 【问题描述】:我今天看到了这段代码
if (translatedText.contains("â")) translatedText = translatedText.replace("â", "a");
if (translatedText.contains("ê")) translatedText = translatedText.replace("ê", "e");
...
这样的行有 22 行,我想知道在替换之前使用“ifs”有什么意义。我理解它的工作方式是,我们每行读取两次字符串,而直接调用 replace 方法在没有要替换的内容时会产生相同的效果,而在有要替换的内容时会更快。
但这只是我猜它的工作原理。有人可以确认或更正我吗?
还有第二个问题。我们正在对每个元音和每个符号“á”、“à”、“â”和“ä”进行替换。我敢打赌,在 Java 中有更好的方法来做到这一点。有什么建议吗?
谢谢。
【问题讨论】:
你为什么要这样做?我很确定它背后的要求是一个错误-我不是要评判什么,我只是相信我们可以在更深层次上帮助你 @Sebas 我想,这不是他的代码——他刚遇到它,想知道是否需要 如果代码中的操作是在条件检查之后执行的,那么它也执行得最好,否则它仍然运行。 对于if
condition你需要查看你的数据长度和你的无效字符的频率,如果长度比较大那么我建议直接去替换
惊喜接受;但你是老板;-)
【参考方案1】:
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();
【讨论】:
恭喜。 500K 派对怎么样? @GhostCat: :-) 似乎只有你注意到了。 @GhostCat:好的,你注意到了。 :-) (事实上,之前似乎总共发生了 12 次……然后是克劳德,幸运的 13 次!) 我在此保证:赚到 500K 后,我会简单地邀请整个 SO 参加庆祝派对……但考虑到今天投票的速度有多慢,嗯,嗯,那将需要一个同时。 @GhostCat 126k 似乎更近了,:)【参考方案2】:关于“性能”:这可能真的取决于 JVM 版本;换句话说:取决于replace()
更改的实施,如果有,可以为您节省一些正则表达式匹配器成本;或不。
关于第二个问题:基本上你有很多重复的代码。一种解决方法:
你可以定义一些静态的 final 字段,比如:
Map<String, String> replacements = new HashMap<>();
然后填写:
replacements.put("â", "a");
...
然后用循环替换当前代码,该循环迭代该映射的条目,使用每个键/值作为 replace() 调用的参数。
或者,如另一个答案所示,您执行类似
的操作replacements.put("[áàâä]", "a");
稍后使用 replaceAll()。
【讨论】:
【参考方案3】:如果您希望摆脱明显多余的if
语句而不导致性能损失,那么快速的解决方案是改用replace(char, char)
:
translatedText = translatedText.replace('â', 'a');
translatedText = translatedText.replace('ê', 'e');
这完全避免了正则表达式,无论是显式的还是隐藏的,并且在我的 Java 8 中,如果没有替换,也可以避免创建一个新的 String
。
是否还有更好的方法取决于包括口味在内的几个因素。其他几个答案的想法很有希望。
【讨论】:
【参考方案4】:您可以使用正则表达式将所有不需要的字符替换为您的字符
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
【讨论】:
他的用例也包括“ê”,因此您需要为每个字符进行映射。 对于每个“目标”-char @runDOSrun 的调用仍将减少到一个。 @Fildor 正确,但它没有提供if
s 的替代方案。
@runDOSrun 好吧,Pavneet 没有明确说明这一点,但我猜他会放弃if
s。以上是关于在替换之前检查字符串是不是包含子字符串是不是值得?的主要内容,如果未能解决你的问题,请参考以下文章