String replace()和replaceAll()的区别

318
除了后者使用正则表达式之外,java.lang.String的replace()和replaceAll()方法有什么区别?对于简单的替换,比如用/替换.,有什么区别吗?

看一下这个提交。 - jumping_monkey
13个回答

249
java.lang.String中,replace方法可以接受一对字符或一对CharSequence(String实现了CharSequence接口,所以它也可以接受一对字符串)。replace方法将替换所有出现的字符或CharSequence
另一方面,replaceFirstreplaceAll的第一个String参数是正则表达式(regex)。
使用错误的函数可能会导致微妙的错误。

来自java.lang.String的相关部分:

  • String replace(char oldChar, char newChar)
    返回一个新的字符串,该字符串将此字符串中所有出现的oldChar替换为newChar。

  • String replace(CharSequence target, CharSequence replacement)
    将此字符串中与目标序列匹配的每个子字符串替换为指定的替换序列。

  • String replaceAll(String regex, String replacement)
    将此字符串中与给定正则表达式匹配的每个子字符串替换为给定的替换字符串。

  • String replaceFirst(String regex, String replacement)
    将此字符串中与给定正则表达式匹配的第一个子字符串替换为给定的替换字符串。


41
另外,根据Java文档,每次调用str.replaceAll(regex, repl)Pattern.compile(regex).matcher(str).replaceAll(repl)相同。因此,根据使用频率的不同会有很大的开销。 - user845279
9
很有趣您这么说,因为String#replace(target, replacement)做的事情与String#replaceAll相同,只不过它会对字符串加引号: Pattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));。请问,使用String#replaceString#replaceAll更快的原因是什么呢?看起来并不是这样,因为String#replace只是执行了额外的操作。 - Horsey
3
好的,我会尽力以最简洁的方式进行翻译。只是好奇,在这个回答中,与 replaceAll 的明确比较在哪里?该回答更多地涉及 replace - Manuel Jordan
1
这意味着由于正则表达式匹配,replaceAll() 的成本会更高,不是吗? - wonder

157

8
感谢你澄清这只是正则表达式。但我真希望它们可以把它命名为replaceWithRegex()而不是replaceAll()。 - HopeKing
澄清:replaceAll() 使用正则表达式,replace() 使用 CharSequence。 - Johnny Five
6
@JohnnyFive,这让情况更加混乱了。正则表达式不是一种类型,而是CharSequence是。replace()replaceAll()都可以“使用CharSequence”进行操作。区别在于,replaceAll()将给定的CharSequence视为正则表达式,因此寻找_正则表达式匹配项_,而replace()将给定的CharSequence视为普通搜索文本,因此寻找其中的_出现次数_。 - SantiBailors
替换所有的!那就是我想听到的! - MbPCM

83

无论是replace()还是replaceAll()函数都能替换字符串中的所有出现。

例子

我总觉得例子有助于理解它们之间的区别。

replace()

如果您只想用另一个字符或字符串(实际上是CharSequence)替换某些字符,请使用replace()函数。

例子 1

将字符串中所有的字符x替换为o

String myString = "__x___x___x_x____xx_";

char oldChar = 'x';
char newChar = 'o';

String newString = myString.replace(oldChar, newChar);
// __o___o___o_o____oo_

例子 2

将字符串中所有出现的 fish 替换为 sheep

String myString = "one fish, two fish, three fish";

String target = "fish";
String replacement = "sheep";

String newString = myString.replace(target, replacement);
// one sheep, two sheep, three sheep

replaceAll()

若要使用 正则表达式模式,请使用replaceAll()

示例 3

将任何数字替换为x

String myString = "__1_6____3__6_345____0";

String regex = "\\d";
String replacement = "x";

String newString = myString.replaceAll(regex, replacement); 
// __x_x____x__x_xxx____x

示例4

移除所有空格。

String myString = "   Horse         Cow\n\n   \r Camel \t\t Sheep \n Goat        ";

String regex = "\\s";
String replacement = "";

String newString = myString.replaceAll(regex, replacement); 
// HorseCowCamelSheepGoat

参见

文档

正则表达式


43

replace()方法被重载,可以接受一个基本的char和一个CharSequence作为参数。

就性能而言,replace()方法比replaceAll()方法稍微快一些,因为后者首先编译正则表达式模式,然后进行匹配,最后才替换,而前者仅匹配提供的参数并替换。

由于我们知道正则表达式模式匹配稍微复杂,因此更喜欢在可能的情况下选择使用replace()而不是replaceAll()

例如,对于像您提到的简单的替换,最好使用:

replace('.', '\\');

使用以下方式代替:

replaceAll("\\.", "\\\\");

注意:上述转换方法的参数依赖于系统。


6
以下是翻译的结果:即使是替换操作,该方法也是相同的。从Java String文档中获取:public String replace(CharSequence target, CharSequence replacement) { return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString())); } - Prateek
2
@Prateek:在jdk8之后,String :: replace不再使用Pattern:https://hg.openjdk.java.net/jdk9/jdk9/jdk/file/65464a307408/src/java.base/share/classes/java/lang/String.java#l2152,jdk11也是如此。 - Franck
同意,在Java 8中,这两种方法实际上几乎是相同的,因为它们的实现中都出现了Pattern.compile(...)内容/部分,似乎replace在如何定义/发送第一个参数方面更简单。它不需要“\”。此外,自Java 1.5以来就提供了replace,而replaceAll则自1.4以来可用。 - Manuel Jordan

7
  1. replace()和replaceAll()接受两个参数,并用第二个子字符串(第二个参数)替换字符串中的第一个子字符串(第一个参数)的所有出现。
  2. replace()接受一对char或charsequence,而replaceAll()接受一对regex。
  3. 并不是replace()比replaceAll()更快,因为它们在实现中都使用相同的代码

    Pattern.compile(regex).matcher(this).replaceAll(replacement);

现在的问题是何时使用replace和replaceAll? 当您想要用另一个子字符串替换任意位置出现的子字符串时,请使用replace()。但是,如果您有一些特定偏好或条件,例如仅替换字符串开头或结尾的子字符串,请使用replaceAll()。以下是一些示例,以证明我的观点:

String str = new String("==qwerty==").replaceAll("^==", "?"); \\str: "?qwerty=="
String str = new String("==qwerty==").replaceAll("==$", "?"); \\str: "==qwerty?"
String str = new String("===qwerty==").replaceAll("(=)+", "?"); \\str: "?qwerty?"

6
它们并不是完全相同的实现。replace方法不会调用Pattern.compile(regex).matcher(this).replaceAll(replacement);,而是调用了Pattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString())); - ChiefTwoPencils
2
replaceAll()接受一对正则表达式。为什么搜索字符串和替换字符串都要是正则表达式?用什么替换出现次数?使用正则表达式吗?当然,只有第一个参数是正则表达式(搜索字符串)。第二个参数不是正则表达式(替换字符串)。 - SantiBailors

4

为了更好地举例说明两者如何在下面的代码中工作:

public static void main(String[] args)
{
    String s = "My\\s aaab\\s is\\s aaab\\s name";
    String s1 = s.replace("\\s", "c");
    System.out.println(s1);
    String s2 = s.replaceAll("\\s", "c");
    System.out.println(s2);
}

输出:

Myc aaabc isc aaabc name
My\scaaab\scis\scaaab\scname

解释

s.replace将字符串s中的“\s”序列替换为c。因此,第一行输出。 s.replaceAll将\\s视为正则表达式(等同于空格),并用c替换空格。在字符串s中,\\s使用第一个\进行转义并变成\s。

Intellij Idea足够聪明,能够通知您有关使用情况。如果您仔细观察下面的图像,您将看到Intellij idea对replace和replaceAll使用的解释差异。

enter image description here


3
String replace(char oldChar, char newChar)

返回一个新的字符串,其中所有出现在该字符串中的oldChar都被替换为newChar。
String replaceAll(String regex, String replacement

使用给定的替换字符串,将此字符串中与给定正则表达式匹配的每个子字符串替换。


1

虽然这是一个老帖子,但我对Java还比较陌生,发现了其中的一些奇怪之处。我使用了String.replaceAll()方法,但却得到了不可预测的结果。

像这样的情况会破坏字符串:

sUrl = sUrl.replaceAll( "./", "//").replaceAll( "//", "/");

所以我设计了这个函数来解决这个奇怪的问题:
//String.replaceAll does not work OK, that's why this function is here
public String strReplace( String s1, String s2, String s ) 
{
    if((( s == null ) || (s.length() == 0 )) || (( s1 == null ) || (s1.length() == 0 )))
     { return s; }

   while( (s != null) && (s.indexOf( s1 ) >= 0) )
    { s = s.replace( s1, s2 ); }
  return s;
}

能让你做什么:

sUrl=this.strReplace("./", "//", sUrl );
sUrl=this.strReplace( "//", "/", sUrl );

1
String.replaceAll() 期望使用正则表达式而不是字面参数,这就是为什么你会得到“不可预测”的结果(实际上这些结果是非常可预测的)。String.replace() 则可以按照你想要的方式工作。 - Nadar
1
通常情况下,当我们从Java中得到意外结果时,与其设计一个新的函数来解决问题,不如假设这些结果是正确的,而我们可能是误解了我们正在使用的Java功能。 - SantiBailors
1
我知道replaceAll使用正则表达式..但是这个简单的函数strReplace解决了我的问题。 - Mark Amabile

1

1

正如wickeD的回答中所暗示的那样,对于replaceAll方法,替换字符串在replace和replaceAll之间处理方式是不同的。我期望a[3]和a[4]具有相同的值,但它们是不同的。

public static void main(String[] args) {
    String[] a = new String[5];
    a[0] = "\\";
    a[1] = "X";
    a[2] = a[0] + a[1];
    a[3] = a[1].replaceAll("X", a[0] + "X");
    a[4] = a[1].replace("X", a[0] + "X");

    for (String s : a) {
        System.out.println(s + "\t" + s.length());
    }
}

这段话的翻译是:“这个的输出是:”。
\   1
X   1
\X  2
X   1
\X  2

这与Perl不同,替换文本时不需要额外的转义级别:
#!/bin/perl
$esc = "\\";
$s = "X";

$s =~ s/X/${esc}X/;
print "$s " . length($s) . "\n";

打印\X 2

这可能会很麻烦,因为当尝试使用java.sql.DatabaseMetaData.getSearchStringEscape()返回的值与replaceAll()一起使用时。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接