String replace() 和 replaceAll() 的区别

Posted

技术标签:

【中文标题】String replace() 和 replaceAll() 的区别【英文标题】:Difference between String replace() and replaceAll() 【发布时间】:2012-06-05 08:55:55 【问题描述】:

java.lang.String 的replace()replaceAll() 方法有什么区别, 除了以后使用正则表达式?对于简单的替换,例如,将 . 替换为 / , 有什么区别吗?

【问题讨论】:

【参考方案1】:

java.lang.String 中,replace 方法采用一对char 或一对CharSequence(其中String 是一个子类,因此它很乐意采用一对String)。 replace 方法将替换所有出现的字符或CharSequence。另一方面,replaceFirstreplaceAll 的第一个 String 参数是正则表达式 (regex)。使用错误的函数可能会导致细微的错误。

【讨论】:

此外,根据 java 文档,对str.replaceAll(regex, repl) 的每次调用都与Pattern.compile(regex).matcher(str).replaceAll(repl) 相同。所以有很大的开销取决于它的使用量。 @user845279 有趣的是你会说因为String#replace(target, replacement) 做同样的事情,除了它引用字符串:Pattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString())); 有什么原因String#replace 会比String#replaceAll 快吗?看起来不像,因为String#replace 只是执行额外的操作。 只是好奇,在这个答案中,与replaceAll 的明确比较在哪里。答案更多是关于replace 这意味着 replaceAll() 由于正则表达式匹配而成本更高?不是吗?【参考方案2】:

问:java.lang.String方法replace()replaceAll()有什么区别,除了后者使用正则表达式。

答:只是正则表达式。它们都全部替换 :)

http://docs.oracle.com/javase/8/docs/api/java/lang/String.html

PS:

还有一个replaceFirst()(需要一个正则表达式)

【讨论】:

感谢您澄清它只是正则表达式。我多么希望他们将其命名为 replaceWithRegex() 而不是 replaceAll() 澄清: replaceAll() 适用于正则表达式,replace() 适用于 CharSequence @JohnnyFive 这让它更加混乱。正则表达式不是类型,CharSequence 是。 replace()replaceAll() “与 CharSequence 一起工作”。就是replaceAll() 将给定的CharSequence 视为正则表达式,因此它会查找正则表达式匹配,而replace() 将给定的CharSequence 视为纯搜索文本,因此它会查找它的发生【参考方案3】:

replace()replaceAll() 都替换字符串中的所有匹配项。

示例

我总能找到有助于理解差异的示例。

replace()

如果您只想用另一个char 替换一些char 或用另一个String(实际上是CharSequence)替换一些String,请使用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()

如果您想使用regular expression pattern,请使用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

另见

文档

replace(char oldChar, char newChar) replace(CharSequence target, CharSequence replacement) replaceAll(String regex, String replacement) replaceFirst(String regex, String replacement)

正则表达式

Tutorial List of patterns

【讨论】:

【参考方案4】:

replace() 方法被重载以接受原始 charCharSequence 作为参数。

现在就性能而言,replace() 方法比 replaceAll() 快一点,因为后者首先编译正则表达式模式,然后在最终替换之前匹配,而前者只是匹配提供的参数并替换.

由于我们知道正则表达式模式匹配有点复杂,因此速度较慢,因此建议尽可能使用replace() 而不是replaceAll()

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

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

代替:

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

注意:上述转换方法参数是系统相关的。

【讨论】:

即使替换也一样,来自 java String docs :: public String replace(CharSequence target, CharSequence replacement) return Pattern.compile(target.toString(), Pattern.LITERAL) .matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString())); @Prateek:在 jdk8 之后,String::replace 不再使用 Pattern:hg.openjdk.java.net/jdk9/jdk9/jdk/file/65464a307408/src/…,在 jdk11 中也是如此。 同意,在 Java 8 中,实际上这两种方法几乎是相同的,因为它们的实现中都出现了 Pattern.compile(...) 内容/部分,似乎replace 关于如何定义/发送第一个参数并不复杂。它不需要 "\" 。此外,replace 从 Java 开始可用,1.5replaceAll1.4 开始可用【参考方案5】:
    replace() 和 replaceAll() 都接受两个参数,并用第二个子字符串(第二个参数)替换字符串中所有出现的第一个子字符串(第一个参数)。 replace() 接受一对 char 或 charsequence,replaceAll() 接受一对正则表达式。

    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?"

【讨论】:

它们不是完全相同的实现。 replace 不调用 Pattern.compile(regex).matcher(this).replaceAll(replacement);。它调用Pattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString())); replaceAll() 接受一对正则表达式 为什么搜索字符串 和替换字符串 都是正则表达式?这些事件将被替换为什么?用正则表达式?当然只有第一个参数是一个正则表达式(搜索字符串)。第二个不是正则表达式(替换字符串)。【参考方案6】:
String replace(char oldChar, char newChar)

返回一个新字符串,该字符串是用 newChar 替换此字符串中所有出现的 oldChar。

String replaceAll(String regex, String replacement

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

【讨论】:

【参考方案7】:

用一个例子来说明两者在以下代码中的工作方式:

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 用 c 替换“\\s”字符序列。因此,第一行的输出。 s.replaceAll 将 \\s 视为一个正则表达式(相当于空格)并用 c 替换空格。 String s 中的 \\s 与遇到的第一个 \ 一起转义并变为 \s。

Intellij Idea 非常聪明,可以通知您使用情况。如果您仔细查看下图,您会发现 Intellij idea 对 replace 和 replaceAll 用法的解释不同。

【讨论】:

【参考方案8】:

正如 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/$escX/;
print "$s " . length($s) . "\n";

打印 \X 2

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

【讨论】:

【参考方案9】:

从 Java 9 开始,替换方法有了一些优化。

在 Java 8 中,它使用正则表达式。

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

从 Java 9 开始。

还有 Stringlatin 的实现。

哪个表现更好。

https://medium.com/madhash/composite-pattern-in-a-nutshell-ad1bf78479cc?source=post_internal_links---------2------------------

【讨论】:

【参考方案10】:

我知道旧线程,但我对 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 );

【讨论】:

String.replaceAll() 期望 regular expressions 不是文字参数,这就是为什么您会得到“不可预测”(实际上非​​常可预测)结果的原因。 String.replace() 以您想要的方式工作。 根据经验,当我们从 Java 中得到意想不到的结果时,与其设计一个新函数来解决这个问题,不如假设这些结果是完全正确的,并且我们误解了 Java我们正在使用的功能。【参考方案11】:

replace() 方法不使用正则表达式模式,而 replaceAll() 方法使用正则表达式模式。所以replace() 的执行速度比replaceAll() 快​​。

【讨论】:

那不是真的。如果您查看替换的来源,您会发现它也使用了模式和匹配器(即正则表达式) 从 Java 9 开始,这是真的。【参考方案12】:

要添加到已经选择的“最佳答案”(以及其他与 Suragch 一样好的答案),String.replace() 会受到替换连续字符的限制(因此采用CharSequence)。但是,String.replaceAll() 不受仅替换连续字符的限制。只要您的正则表达式是以这种方式构造的,您就可以替换非连续字符。

同样(最重要也是最明显的),replace() 只能替换文字值;而replaceAll 可以替换“like”序列(不一定相同)。

【讨论】:

【参考方案13】:

replace 适用于 char 数据类型,而 replaceAll 适用于 String 数据类型,并且都将第一个参数的所有出现替换为第二个参数。

【讨论】:

以上是关于String replace() 和 replaceAll() 的区别的主要内容,如果未能解决你的问题,请参考以下文章

java 中replace方法?

String 类中replace 和replaceAll方法的区别

preg_replace/string_replace 符号 - 或 * 到空格

替代 String.Replace

String replace() 和 replaceAll() 的区别

string replace和replaceAll的区别