Różnica między String replace () i replaceAll ()

221

Jaka jest różnica między java.lang.String replace()i replaceAll()metodami, inne niż później używa wyrażenia regularnego? W przypadku prostych podstawień podobnych, zastępujących .ze / jest jakaś różnica?

Jijoy
źródło

Odpowiedzi:

174

W java.lang.StringThe replacemetoda albo trwa parę char lub parę CharSequence„s (z których String jest podklasą, więc ona szczęśliwie wziąć parę struny). replaceMetoda zastąpi wszystkie wystąpienia char lub CharSequence. Z drugiej strony oba Stringargumenty do replaceFirsti replaceAllsą wyrażeniami regularnymi (regex). Korzystanie z niewłaściwej funkcji może prowadzić do subtelnych błędów.

emilan
źródło
30
Ponadto, zgodnie z dokumentacją Java, każde wywołanie do str.replaceAll(regex, repl)jest takie samo jak Pattern.compile(regex).matcher(str).replaceAll(repl). Jest więc duży narzut w zależności od tego, ile zużywa się.
user845279
4
@ user845279 Ciekawe, że powiedziałbyś, że skoro String#replace(target, replacement)robi to samo, tyle że cytuje ciągi znaków: Pattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));czy istnieje jakiś powód, dla którego String#replacebyłoby szybsze niż String#replaceAll? Nie wyglądałoby na to, ponieważ String#replacepo prostu wykonuje dodatkowe operacje.
Horsey,
1
Ciekawe, w tej odpowiedzi jest wyraźne porównanie replaceAll. Odpowiedź brzmi bardziejreplace
Manuel Jordan,
oznacza to, że replaceAll () byłoby droższe z powodu dopasowania wyrażenia regularnego?
zastanawiam się
97

P: Jaka jest różnica między java.lang.Stringmetodami replace()i replaceAll(), poza tym, że później używa wyrażenia regularnego.

Odp .: Po prostu regex. Oboje zastępują wszystko :)

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

PS:

Jest też replaceFirst()(który wymaga wyrażenia regularnego)

paulsm4
źródło
1
Dziękuję za wyjaśnienie, że to tylko wyrażenie regularne. Jak chciałbym, żeby go nazwali replaceWithRegex () zamiast replaceAll ()
HopeKing
Wyjaśnienie: replaceAll () działa z wyrażeniami regularnymi, replace () działa z CharSequence
Johnny Five
2
@JohnnyFive To sprawia, że ​​jest to bardziej mylące. Wyrażenie regularne nie jest typem, CharSequencejest. Zarówno replace()i replaceAll()„praca z CharSequence”. Jest tak, że replaceAll()traktuje podane CharSequencewyrażenie jako wyrażenie regularne, więc szuka dopasowań wyrażenia regularnego , podczas gdy replace()uważa podane CharSequencejako zwykły tekst wyszukiwania, więc szuka jego wystąpienia .
SantiBailors
43

Zarówno replace()i replaceAll()zamień wszystkie wystąpienia w ciągu.

Przykłady

Zawsze znajduję przykłady pomocne w zrozumieniu różnic.

replace()

Użyj, replace()jeśli chcesz po prostu zamienić niektóre na charinne charlub niektóre na Stringinne String(faktycznie CharSequence).

Przykład 1

Zastąpić wszystkie wystąpienia znaku xz 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_

Przykład 2

Zastąpić wszystkie wystąpienia napisu fishz 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()

Użyj, replaceAll()jeśli chcesz użyć wzorca wyrażenia regularnego .

Przykład 3

Zamień dowolny numer na 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

Przykład 4

Usuń wszystkie białe znaki.

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

Zobacz też

Dokumentacja

Wyrażenia regularne

Suragch
źródło
34

replace()Metoda jest przeciążony do zaakceptowania zarówno prymitywne chari CharSequencejako argumenty.

Jeśli chodzi o wydajność, replace()metoda jest nieco szybsza niż replaceAll()dlatego, że ta ostatnia najpierw kompiluje wzorzec wyrażenia regularnego, a następnie dopasowuje przed ostatecznym zastąpieniem, podczas gdy pierwsza po prostu dopasowuje podany argument i zamienia.

Ponieważ wiemy, że dopasowanie regex wzorzec jest nieco bardziej skomplikowana, a co za tym idzie wolniej, a preferowanie replace()ponad replaceAll()sugeruje w miarę możliwości.

Na przykład w przypadku prostych zamian, takich jak wspomniane, lepiej użyć:

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

zamiast:

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

Uwaga: powyższe argumenty metody konwersji zależą od systemu.

Surender Thakran
źródło
6
Nawet replace również zrobić to samo, z java String docs :: public String replace (CharSequence target, CharSequence replace) {return Pattern.compile (target.toString (), Pattern.LITERAL) .matcher (this) .replaceAll (Matcher.quoteReplacement (replace.toString ())); }
Prateek
@Prateek: po jdk8 String :: replace nie używa już Wzorca: hg.openjdk.java.net/jdk9/jdk9/jdk/file/65464a307408/src/... , to samo w jdk11.
Franck
Zgadzam się, w Javie 8 praktycznie obie metody są prawie takie same, ponieważ obie pojawiają się w Pattern.compile(...)treści / części w swoich implementacjach, wydaje się, że replacejest mniej skomplikowane w zakresie definiowania / wysyłania pierwszego argumentu. To nie wymaga "\". Ponadto replacejest dostępny od Java 1.5i replaceAllod1.4
Manuel Jordan
3
String replace(char oldChar, char newChar)

Zwraca nowy ciąg wynikający z zamiany wszystkich wystąpień oldChar w tym ciągu na newChar.

String replaceAll(String regex, String replacement

Zastępuje każdy podciąg tego łańcucha, który pasuje do podanego wyrażenia regularnego z podanym zamiennikiem.

S. Rahul
źródło
3
  1. Zarówno replace (), jak i replaceAll () akceptuje dwa argumenty i zastępuje wszystkie wystąpienia pierwszego podłańcucha (pierwszy argument) w ciągu drugim podciągiem (drugi argument).
  2. replace () akceptuje parę znaków char lub ciąg znaków, a replaceAll () akceptuje parę wyrażeń regularnych.
  3. Nie jest prawdą, że replace () działa szybciej niż replaceAll (), ponieważ oba wykorzystują ten sam kod w swojej implementacji

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

Teraz pytanie brzmi: kiedy użyć replace i kiedy użyć replaceAll (). Jeśli chcesz zastąpić podciąg innym podciągiem, niezależnie od miejsca jego wystąpienia w ciągu, użyj replace (). Ale jeśli masz jakieś szczególne preferencje lub warunki, takie jak zamień tylko te podciągi na początku lub na końcu łańcucha, użyj replaceAll (). Oto kilka przykładów, które mogą potwierdzić mój punkt widzenia:

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
źródło
4
Nie są to dokładnie te same wdrożenia. replacenie dzwoni Pattern.compile(regex).matcher(this).replaceAll(replacement);. WzywaPattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
ChiefTwoPencils
replaceAll () akceptuje parę wyrażeń regularnych Dlaczego zarówno szukany ciąg, jak i ciąg zastępujący byłyby wyrażeniem regularnym? Jakie zdarzenia zostaną zastąpione? Z wyrażeniem regularnym? Oczywiście tylko pierwszy argument jest wyrażeniem regularnym (ciąg wyszukiwania). Drugi nie jest wyrażeniem regularnym (ciąg zastępujący).
SantiBailors
1

Jak wspomniano w odpowiedzi wickeD, z replaceAll ciąg zastępujący jest traktowany inaczej w zastępstwie i replaceAll. Oczekiwałem, że [3] i [4] będą miały tę samą wartość, ale są różne.

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

Wynikiem tego jest:

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

Różni się to od perla, w którym zamiana nie wymaga dodatkowego poziomu ucieczki:

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

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

który drukuje \ X 2

Może to być dość uciążliwe, jak przy próbie użycia wartości zwracanej przez java.sql.DatabaseMetaData.getSearchStringEscape () z replaceAll ().

Keith Crews
źródło
0

Stary wątek Wiem, ale jestem trochę nowy w Javie i odkryłem jedną z dziwnych rzeczy. Użyłem, String.replaceAll()ale otrzymuję nieprzewidywalne wyniki.

Coś w stylu bałaganu:

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

Więc zaprojektowałem tę funkcję, aby obejść ten dziwny problem:

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

Które sprawiają, że możesz zrobić:

sUrl=this.strReplace("./", "//", sUrl );
sUrl=this.strReplace( "//", "/", sUrl );
Codebeat
źródło
1
String.replaceAll()oczekuje wyrażeń regularnych, a nie dosłownych argumentów, dlatego otrzymujesz wyniki „nieprzewidywalne” (które są naprawdę bardzo przewidywalne). String.replace()działa tak, jak chcesz.
Nadar
Jako ogólną zasadę, gdy otrzymujemy nieoczekiwane wyniki z Javy, zamiast projektować nową funkcję, aby obejść ten problem, lepiej założyć, że te wyniki są całkowicie błędne i że źle rozumiemy używaną funkcjonalność Javy.
SantiBailors
0

Aby dodać do już wybranej „najlepszej odpowiedzi” (i innych, które są tak samo dobre jak Suragch), String.replace()ogranicza się zastępowanie znaków, które są sekwencyjne (w ten sposób przyjmując CharSequence). Nie String.replaceAll()jest jednak ograniczany przez zamianę tylko znaków sekwencyjnych. Można zastąpić znaki niesekwencyjne, o ile wyrażenie regularne jest zbudowane w taki sposób.

Również (co najważniejsze i boleśnie oczywiste) replace()może jedynie zastąpić wartości dosłowne; podczas gdy replaceAllmoże zastąpić sekwencje „podobne” (niekoniecznie identyczne).

hfontanez
źródło
-1

replace()metoda nie używa wzorca wyrażenia regularnego, podczas gdy replaceAll()metoda używa wzorca wyrażenia regularnego. Więc replace()działa szybciej niż replaceAll().

mężczyzna
źródło
3
to nieprawda. Jeśli spojrzysz na źródło zastępowania, zobaczysz, że użyło ono również Wzorca i Matchera (tj. Regex)
xtrakBandit
-5

replace działa na typie danych char, ale replaceAll działa na typie danych String i oba zastępują wszystkie wystąpienia pierwszego argumentu drugim argumentem.

Pramod Kumar
źródło