Різниця між String substitute () та substituAll ()


221

Яка різниця між java.lang.String 's replace()та replaceAll()методами, за винятком яких пізніше використовуються регулярні вирази? Для простих замін подобається, замінюють .з / , чи є різниця?

Відповіді:


174

У java.lang.String, replaceметод або бере пару знаків або пару CharSequences (з яких String є підкласом, тому він із задоволенням візьме пару String's). replaceМетод замінить всі входження напівкоксу або CharSequence. З іншого боку, обидва Stringаргументи до replaceFirstта replaceAllє регулярними виразами (регулярні вирази). Використання неправильної функції може призвести до тонких помилок.


30
Крім того, згідно з документами java, кожен дзвінок до того str.replaceAll(regex, repl)ж, що і Pattern.compile(regex).matcher(str).replaceAll(repl). Отже, великі накладні витрати залежать від того, наскільки він використовується.
user845279

4
@ user845279 Цікаво, ви б сказали, що оскільки String#replace(target, replacement)робить те ж саме, за винятком цитування рядків: Pattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));Чи є якась причина, чому String#replaceбуло б швидше, ніж String#replaceAll? Здавалося б, не так, оскільки він String#replaceвиконує додаткові операції.
Horsey

1
Просто цікаво, у цій відповіді де явне порівняння replaceAll. Відповідь детальніше проreplace
Мануель Йордан

це означає, що FollowAll () буде дорожчим через збігу регулярних виразів?
диво

98

З: Яка різниця між java.lang.Stringметодами replace()та replaceAll(), окрім того, що пізніше використовується регулярний вираз.

A: Просто виразка. Вони обидва замінюють усіх :)

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

PS:

Існує також replaceFirst()(що займає регулярний вираз)


1
Thx для уточнення, що це просто регулярний вираз. Як би я хотів, щоб вони назвали його заміноюWithRegex () замість substituAll ()
HopeKing

Уточнення: substituAll () працює з регулярними виразами, заміна () працює з CharSequence
Johnny Five

2
@JohnnyFive Це робить його більш заплутаним. Регулярний вираз не є типом, CharSequenceє. І те, replace()і replaceAll()«працювати з CharSequence». Це те, що replaceAll()розглядає поданий CharSequenceяк регулярний вираз, тому він шукає збіги регулярних виразів , тоді як replace()розглядає дані CharSequenceяк звичайний текст пошуку, тому він шукає його події .
SantiBailors

43

Обидва replace()і replaceAll()замінюють усі події в рядку.

Приклади

Я завжди вважаю приклади корисними для розуміння відмінностей.

replace()

Використовуйте, replace()якщо ви просто хочете замінити деякі charна інші charабо інші Stringна інші String(насправді CharSequence).

Приклад 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

Дивитися також

Документація

Регулярні вирази


34

replace()Метод перевантажений , щоб прийняти як примітивний charі в CharSequenceякості аргументів.

Що ж стосується продуктивності, replace()метод трохи швидший, ніжreplaceAll() через те, що останній спочатку компілює шаблон регулярного вираження, а потім відповідає перед остаточною заміною, тоді як перший просто відповідає поданому аргументу та замінює.

Оскільки ми знаємо , що узгодження регулярних виразів шаблону є трохи більш складним і , отже , повільніше, потім віддаючи перевагу replace()більшreplaceAll() пропонується щоразу , коли це можливо.

Наприклад, для простих замін, як ви згадали, краще використовувати:

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

замість:

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

Примітка: наведені вище аргументи методу перетворення залежать від системи.


6
Навіть заміни також зробити те ж саме, з java String docs :: public String замінити (CharSequence target, CharSequence substitution) {return Pattern.compile (target.toString (), Pattern.LITERAL) .matcher (this) .replaceAll (Matcher.quoteReplacement) (substitu.toString ())); }
Prateek

@Prateek: після jdk8, String :: zamjeна більше не використовує Шаблон: hg.openjdk.java.net/jdk9/jdk9/jdk/file/65464a307408/src/… , той же в jdk11.
Франк

Погодьтеся, в Java 8 практично обидва способи майже однакові, оскільки обидва видаються, що Pattern.compile(...)вміст / частина в їх реалізації, здається replace, менш складний щодо визначення / відправки першого аргументу. Це не вимагає "\". Крім того replace, доступний з Java 1.5та replaceAllз1.4
Мануель Йордан

3
String replace(char oldChar, char newChar)

Повертає новий рядок, що виникає в результаті заміни всіх входжень oldChar у цій рядку на новийChar.

String replaceAll(String regex, String replacement

Замінює кожну підрядку цього рядка, яка відповідає заданому регулярному виразу із заданою заміною.


3
  1. І заміну (), і замінаAll () приймає два аргументи і замінює всі входження в першу підрядку (перший аргумент) в рядку з другою підрядкою (другий аргумент).
  2. substitu () приймає пару знаків char або charsequence, а substituAll () приймає пару регулярних виразів.
  3. Це неправда, що substitu (працює) швидше, ніж substituAll (), оскільки обидва використовують один і той же код у своїй реалізації

    Pattern.compile (regex) .matcher (це) .replaceAll (заміна);

Тепер питання полягає в тому, коли використовувати заміну та коли використовувати замінуAll (). Коли ви хочете замінити підрядку на іншу підрядку, незалежно від місця її виникнення в рядку, використовуйте substitute (). Але якщо у вас є якісь особливі уподобання або умови, такі як замінити лише ці підрядки на початку або в кінці рядка, використовуйте substituAll (). Ось кілька прикладів, які підтверджують мою думку:

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

4
Вони не є точно такою ж реалізацією. replaceне дзвонить Pattern.compile(regex).matcher(this).replaceAll(replacement);. ДзвінкиPattern.compile(target.toString(), Pattern.LITERAL).matcher(this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
ChiefTwoPencils

substituAll () приймає пару регулярних виразів Чому і рядок пошуку, і рядок заміни буде регулярним виразом? Що б замінило події? З регексом? Звичайно, лише перший аргумент - це регулярне вираження (рядок пошуку). Другий - це не регулярний вираз (рядок заміни).
SantiBailors

1

Як згадується у відповіді wickeD, за допомогою stringAll рядок заміни обробляється по-різному між заміною та заміною Все. Я очікував, що [3] і [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 () з substituAll ().


0

Я знаю стару тему, але я щось нове для 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()працює так, як вам хочеться.
Надар

Як правило, коли ми отримуємо несподівані результати від Java, а не розробляємо нову функцію, щоб обійти це, краще припустити, що ці результати є мертвими, і що ми нерозуміємо функціональність Java, яку ми використовуємо.
SantiBailors

0

Додавання до вже вибраного "Найкращого відповіді" (та інших, які так само хороші, як Сурагч), String.replace()обмежується заміною символів, які є послідовними (таким чином, прийнятими CharSequence). Однак,String.replaceAll() не обмежується лише заміною послідовних символів. Ви можете замінювати непослідовні символи, а також, поки ваш регулярний вираз побудований таким чином.

Також (найголовніше і болісно очевидно), replace()може замінити лише буквальні значення; тоді як replaceAllможна замінити "схожі" послідовності (не обов'язково однакові).


-1

replace()метод не використовує шаблон регулярного вираження, тоді як replaceAll()метод використовує шаблон регулярного вираження. Так replace()виконує швидше, ніж replaceAll().


3
це не правда. Якщо ви подивитесь на джерело заміни, ви побачите, що він також використовував Pattern and Matcher (тобто regex)
xtrakBandit

-5

замінити роботи на тип даних char, але замінитиВсі працює на типі даних String і обидва заміняють усі випадки першого аргументу другим аргументом.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.