如何在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