如何在Java中没有正则表达式的情况下只替换一次字符串?

我需要用一个更大的字符串替换动态子字符串,但只需要一次(即第一次匹配)。 String类只提供replace() ,它替换子字符串的所有实例; 有一个replaceFirst()方法,但它只需要regexp而不是常规字符串。 我对使用正则表达式有两个顾虑:

1)我的子串是动态的,所以可能包含奇怪的字符,这些字符在正则表达式中表示其他东西,我不想处理字符转义。

2)这种替换经常发生,我不确定使用正则表达式是否会影响性能。 由于正则表达式本身是动态的,我无法预先编译正则表达式!

我必须在这里遗漏一些东西,因为在我看来这是一个非常基本的东西……是否有一个replaceFirst方法在java franework中的其他地方使用常规字符串?

使用bigString.indexof(smallString)获取大字符串中第一次出现的小字符串的索引(如果没有,则返回-1,在这种情况下,您已完成)。 然后,使用bigString.substring在匹配之前和之后获取大字符串的各个部分,最后将这些部分放在一起,然后将它们放在一起,将中间的替换放在中间。

您应该使用已经过测试且文档齐全的库来支持编写自己的代码!

 StringUtils.replaceOnce("aba", "a", "") = "ba" 

正如劳伦斯建议的那样,你可以像这样使用Pattern.quote

 newString = string.replaceFirst(Pattern.quote(substring), replacement); 

这将创建一个与子字符串字面匹配的新正则表达式。 另一种方法是简单地将子字符串编译为文字正则表达式,如下所示:

 newString = Pattern.compile(substring, Pattern.LITERAL). matcher(string).replaceFirst(replacement); 

这可能稍微有点效率,但也不太清楚。

你也可以手动完成,因为你只想替换第一次出现。 但是正则表达式非常有效,所以不要过早优化!

确保也替换替换中的\s$s 。 这可能是你想要的,因为你不能有任何子组与你的()被删除)。

 newStr = str.replaceFirst(Pattern.quote(target), Matcher.quoteReplacement(replacement)); 

Pattern.quote似乎并不适用于所有情况。 试试`Pattern.quote(“:-)”);

java中的StringBuilder类可以非常容易地用于基于非正则表达式替换另一个字符串。

 private static String replace(String in, String ths, String that) { StringBuilder sb = new StringBuilder(in); int idx = sb.indexOf(ths); while (idx > -1) sb.replace(idx, idx + ths.length(), that); idx = sb.indexOf(ths); } return sb.toString(); } 

解决方案与Pattern

您还可以更改使用字符的字面解释的String.replace方法,以仅替换target字符序列的第一个匹配项:

 /** * Replaces the first subsequence of the source character sequence * that matches the literal target sequence with the specified literal * replacement sequence. * * @param source source sequence on which the replacement is made * @param target the sequence of char values to be replaced * @param replacement the replacement sequence of char values * @return the resulting string */ private static String replaceFirst1(CharSequence source, CharSequence target, CharSequence replacement) { return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( source).replaceFirst(Matcher.quoteReplacement(replacement.toString())); } 

从Pattern.LITERAL的文档:

指定此标志后,指定模式的输入字符串将被视为文字字符序列。 输入序列中的元字符或转义序列将没有特殊含义。

Pattern解决方案

当然,另一种更有效的方法是使用Alex Martelli的提示来产生以下function:

 /** * Replaces the first subsequence of the source string that matches * the literal target string with the specified literal replacement string. * * @param source source string on which the replacement is made * @param target the string to be replaced * @param replacement the replacement string * @return the resulting string */ private static String replaceFirst2(String source, String target, String replacement) { int index = source.indexOf(target); if (index == -1) { return source; } return source.substring(0, index) .concat(replacement) .concat(source.substring(index+target.length())); } 

时间测量

基于10次运行, replaceFirst2方法的执行速度replaceFirst1方法快5倍 。 我已将这两种方法放在一个循环中,重复次数为100.000并得到以下结果,以毫秒为单位:

 方法结果(以毫秒为单位)平均值
 replaceFirst1:220 187 249 186 199 211 172 199 281 199 |  210
 replaceFirst2:40 39 58 45 48 40 42 42 43 59 |  45