Unterschied zwischen String replace () und replaceAll ()

221

Was ist der Unterschied zwischen java.lang.String replace()und replaceAll()Methoden, außer dass später Regex verwendet wird? Gibt es bei einfachen Substitutionen wie Ersetzen .durch / einen Unterschied?

Jijoy
quelle

Antworten:

174

In java.lang.Stringnimmt die replaceMethode entweder ein Paar Zeichen oder ein Paar von CharSequenceZeichen (von denen String eine Unterklasse ist, sodass glücklicherweise ein Paar Zeichenfolgen verwendet werden). Die replaceMethode ersetzt alle Vorkommen eines Zeichens oder CharSequence. Andererseits sind beide StringArgumente für replaceFirstund replaceAllreguläre Ausdrücke (Regex). Die Verwendung der falschen Funktion kann zu subtilen Fehlern führen.

Emilan
quelle
30
Darüber hinaus ist laut Java-Dokumenten jeder Aufruf von str.replaceAll(regex, repl)derselbe wie Pattern.compile(regex).matcher(str).replaceAll(repl). Es gibt also einen großen Overhead, abhängig davon, wie viel es verwendet wird.
user845279
4
@ user845279 Es ist interessant, dass Sie sagen würden, dass da String#replace(target, replacement)das gleiche tut, außer dass es die Zeichenfolgen zitiert: Pattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));Gibt es einen Grund, warum String#replaceschneller als wäre String#replaceAll? Es scheint nicht so, da String#replacenur zusätzliche Operationen ausgeführt werden.
Horsey
1
Nur neugierig, in dieser Antwort, wo ist der explizite Vergleich gegen replaceAll. Die Antwort ist mehr überreplace
Manuel Jordan
Dies bedeutet, dass replaceAll () aufgrund von Regex-Übereinstimmungen teurer wäre, nicht wahr?
Wunder
97

F: Was ist der Unterschied zwischen den java.lang.StringMethoden replace()und replaceAll()ansonsten verwendet der spätere Regex.

A: Nur die Regex. Sie ersetzen beide alle :)

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

PS:

Es gibt auch eine replaceFirst()(die eine Regex nimmt)

paulsm4
quelle
1
Vielen Dank für die Klarstellung, dass es sich nur um den regulären Ausdruck handelt. Wie ich wünschte, sie hätten es replaceWithRegex () anstelle von replaceAll () genannt
HopeKing
Klarstellung: replaceAll () arbeitet mit regulären Ausdrücken, replace () funktioniert mit CharSequence
Johnny Five
2
@ JohnnyFive Das macht es verwirrender. Regulärer Ausdruck ist kein Typ CharSequence. Beides replace()und replaceAll()"arbeiten mit CharSequence". Es ist , dass replaceAll()die gegebene Auffassung CharSequenceals regulärer Ausdruck , so dass es für aussieht Regex -Übereinstimmungen , während replace()der gegebenen betrachtet CharSequenceals einfachen Suchtext , so dass es für aussieht Vorkommen davon.
SantiBailors
43

Beides replace()und replaceAll()alle Vorkommen in der Zeichenfolge ersetzen.

Beispiele

Ich finde immer Beispiele hilfreich, um die Unterschiede zu verstehen.

replace()

Verwenden replace()Sie diese Option, wenn Sie nur einige chardurch andere charoder Stringandere String(tatsächlich CharSequence) durch andere ersetzen möchten .

Beispiel 1

Ersetzen Sie alle Vorkommen des Charakters xdurch 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_

Beispiel 2

Ersetzen Sie alle Vorkommen der Zeichenfolge fishdurch 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()

Verwenden replaceAll()Sie diese Option, wenn Sie ein Muster für reguläre Ausdrücke verwenden möchten .

Beispiel 3

Ersetzen Sie eine beliebige Zahl durch eine 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

Beispiel 4

Entfernen Sie alle Leerzeichen.

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

Siehe auch

Dokumentation

Reguläre Ausdrücke

Suragch
quelle
34

Die replace()Methode ist überladen, um sowohl ein Grundelement charals auch ein CharSequenceals Argumente zu akzeptieren .

Was die Leistung betrifft, ist die replace()Methode etwas schneller als replaceAll()weil die letztere zuerst das Regex-Muster kompiliert und dann übereinstimmt, bevor sie endgültig ersetzt wird, während die erstere einfach mit dem angegebenen Argument übereinstimmt und ersetzt.

Da wir die RegexMuster Matching ist ein wenig komplexer und folglich langsamer wissen, dann lieber replace()über replaceAll()wird vorgeschlagen , wann immer möglich.

Für einfache Substitutionen, wie Sie sie erwähnt haben, ist es beispielsweise besser, Folgendes zu verwenden:

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

anstatt:

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

Hinweis: Die obigen Argumente für die Konvertierungsmethode sind systemabhängig.

Surender Thakran
quelle
6
Auch das Ersetzen macht dasselbe. Von Java String docs :: public String replace (CharSequence-Ziel, CharSequence-Ersetzung) {return Pattern.compile (target.toString (), Pattern.LITERAL) .matcher (this) .replaceAll (Matcher.quoteReplacement (replace.toString ())); }
Prateek
@Prateek: Nach jdk8 verwendet String :: replace kein Muster mehr: hg.openjdk.java.net/jdk9/jdk9/jdk/file/65464a307408/src/… , wie in jdk11.
Franck
Einverstanden, In Java 8 sind praktisch beide Methoden fast gleich, da beide den Pattern.compile(...)Inhalt / Teil in ihren Implementierungen erscheinen, scheint replacees weniger komplex zu sein, wie das erste Argument definiert / gesendet wird. Es erfordert nicht "\". Darüber hinaus replaceist seit Java 1.5und replaceAllseit1.4
Manuel Jordan
3
String replace(char oldChar, char newChar)

Gibt eine neue Zeichenfolge zurück, die sich aus dem Ersetzen aller Vorkommen von oldChar in dieser Zeichenfolge durch newChar ergibt.

String replaceAll(String regex, String replacement

Ersetzt jeden Teilstring dieser Zeichenfolge, der dem angegebenen regulären Ausdruck entspricht, durch den angegebenen Ersatz.

S. Rahul
quelle
3
  1. Sowohl replace () als auch replaceAll () akzeptieren zwei Argumente und ersetzen alle Vorkommen des ersten Teilstrings (erstes Argument) in einer Zeichenfolge durch den zweiten Teilstring (zweites Argument).
  2. replace () akzeptiert ein Paar Zeichen oder Zeichenfolgen und replaceAll () akzeptiert ein Paar Regex.
  3. Es ist nicht wahr, dass replace () schneller funktioniert als replaceAll (), da beide in ihrer Implementierung denselben Code verwenden

    Pattern.compile (Regex) .matcher (this) .replaceAll (Ersatz);

Nun stellt sich die Frage, wann replace und wann replaceAll () verwendet werden sollen. Wenn Sie einen Teilstring unabhängig von seinem Ort in der Zeichenfolge durch einen anderen Teilstring ersetzen möchten, verwenden Sie replace (). Wenn Sie jedoch eine bestimmte Präferenz oder Bedingung haben, z. B. nur die Teilzeichenfolgen am Anfang oder Ende einer Zeichenfolge ersetzen, verwenden Sie replaceAll (). Hier sind einige Beispiele, um meinen Standpunkt zu belegen:

String str = new String("==qwerty==").replaceAll("^==", "?"); \\str: "?qwerty=="
String str = new String("==qwerty==").replaceAll("==$", "?"); \\str: "==qwerty?"
String str = new String("===qwerty==").replaceAll("(=)+", "?"); \\str: "?qwerty?"
Aarya
quelle
4
Sie sind nicht genau die gleiche Implementierung. replacestellt nicht Pattern.compile(regex).matcher(this).replaceAll(replacement);. Es ruftPattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
ChiefTwoPencils
replaceAll () akzeptiert ein Paar Regex Warum sollten sowohl die Suchzeichenfolge als auch die Ersatzzeichenfolge eine Regex sein? Womit würden die Vorkommen ersetzt? Mit einem Regex? Natürlich ist nur das erste Argument ein regulärer Ausdruck (die Suchzeichenfolge). Der zweite ist kein regulärer Ausdruck (die Ersatzzeichenfolge).
SantiBailors
1

Wie in der Antwort von wickeD erwähnt, wird bei replaceAll die Ersetzungszeichenfolge zwischen replace und replaceAll unterschiedlich behandelt. Ich habe erwartet, dass a [3] und a [4] den gleichen Wert haben, aber sie sind unterschiedlich.

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());
    }
}

Die Ausgabe davon ist:

\   1
X   1
\X  2
X   1
\X  2

Dies unterscheidet sich von Perl, bei dem für den Austausch keine zusätzliche Fluchtstufe erforderlich ist:

#!/bin/perl
$esc = "\\";
$s = "X";

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

welches \ X 2 druckt

Dies kann ein ziemliches Ärgernis sein, wenn Sie versuchen, den von java.sql.DatabaseMetaData.getSearchStringEscape () mit replaceAll () zurückgegebenen Wert zu verwenden.

Keith Crews
quelle
0

Alter Thread, den ich kenne, aber ich bin ein bisschen neu in Java und entdecke eines seiner seltsamen Dinge. Ich habe verwendet, String.replaceAll()aber unvorhersehbare Ergebnisse erhalten.

So etwas bringt die Saite durcheinander:

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

Also habe ich diese Funktion entwickelt, um das seltsame Problem zu umgehen:

//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;
}

Was Sie dazu in der Lage macht:

sUrl=this.strReplace("./", "//", sUrl );
sUrl=this.strReplace( "//", "/", sUrl );
Codebeat
quelle
1
String.replaceAll()erwartet reguläre Ausdrücke, keine wörtlichen Argumente, weshalb Sie "unvorhersehbare" (wirklich sehr vorhersehbare) Ergebnisse erhalten. String.replace()funktioniert wie du willst.
Nadar
Als Faustregel gilt, wenn wir unerwartete Ergebnisse von Java erhalten, anstatt eine neue Funktion zu entwickeln, um dies zu umgehen, ist es besser anzunehmen, dass diese Ergebnisse absolut richtig sind und dass wir die von uns verwendete Java-Funktionalität falsch verstehen.
SantiBailors
0

Das Hinzufügen zu der bereits ausgewählten "besten Antwort" (und anderen, die genauso gut sind wie die von Suragch) String.replace()wird durch das Ersetzen von Zeichen eingeschränkt, die sequentiell sind (also nehmen CharSequence). Es String.replaceAll()ist jedoch nicht darauf beschränkt, nur aufeinanderfolgende Zeichen zu ersetzen. Sie können nicht-sequentielle Zeichen ersetzen, solange Ihr regulärer Ausdruck so aufgebaut ist.

Auch (am wichtigsten und schmerzlich offensichtlich) replace()kann nur wörtliche Werte ersetzen; wohingegen replaceAll"ähnliche" Sequenzen ersetzen können (nicht unbedingt identisch).

hfontanez
quelle
-1

replace()Die Methode verwendet kein Regex-Muster, während die replaceAll()Methode das Regex-Muster verwendet. Also geht replace()schneller als replaceAll().

ein Mann
quelle
3
das ist nicht wahr. Wenn Sie sich die Quelle des Ersetzens ansehen, werden Sie sehen, dass dort auch das Muster und der Matcher (dh Regex) verwendet wurden
xtrakBandit
-5

replace funktioniert mit dem Datentyp char, aber replaceAll funktioniert mit dem Datentyp String und beide ersetzen alle Vorkommen des ersten Arguments durch das zweite Argument.

Pramod Kumar
quelle