Питання Як замінити всі входження рядка в JavaScript?


Я маю цей рядок:

"Test abc test test abc test test test abc test test abc"

Робити

str = str.replace('abc', '');

Здається, тільки видалити перше входження в abc у рядку вище. Як я можу замінити? все входження до неї?


3173
2017-07-17 17:53


походження


stackoverflow.com/questions/1137436/... - Canavar
Найпростіше: var str = 'abcabcbabc'; str.replace(/a/g, 'x'); --> 'xbcxbcxbc - FedericoCapaldo
Остерігайтеся того, що варіант Федерико є чудовим, якщо ваш рядок, який буде заміщений, не включає спеціальні символи регулярного виразу. - Andrew
@Andrew Спеціальні символи регулярних виразів можна уникнути як нормальних символів. - modiX
Для тих, хто цікавиться, ви можете уникнути регулярного виразу за зворотною рисою. Наприклад, str.replace (/ \] / g) має працювати, але не str.replace (/] / g), оскільки ']' - це особливий символ регулярного виразу. - ashish-goel


Відповіді:


Для повноти, мені довелося думати про те, який метод я повинен використовувати для цього. Існує два способи зробити це, як це передбачають інші відповіді на цій сторінці.

Примітка: Загалом, розширення вбудованих прототипів у JavaScript зазвичай не рекомендується. Я надаю як розширення на прототипі String просто для цілей ілюстрації, показуючи різні реалізації гіпотетичного стандартного методу на String вбудований прототип.


Регулярне вираження на основі впровадження

String.prototype.replaceAll = function(search, replacement) {
    var target = this;
    return target.replace(new RegExp(search, 'g'), replacement);
};

Спліт та приєднання (функціональне) виконання

String.prototype.replaceAll = function(search, replacement) {
    var target = this;
    return target.split(search).join(replacement);
};

Не знаючи занадто багато того, як регулярні вирази працюють за кадром з точки зору ефективності, я мав тенденцію до розколу та приєднання до реалізації в минулому, не думаючи про ефективність. Коли я дивувався, що було більш ефективним, і якою маргінальністю, я використовував це як виправдання для з'ясування.

На моєму комп'ютері Chrome для ОС Windows 8 реалізація на основі регулярних виразів є найшвидшою, з розділити та приєднатися до реалізації на 53% повільніше. Значення регулярних виразів у два рази швидше для введення lorem ipsum, який я використовував.

Перевірте це орієнтир виконуючи ці дві реалізації один на одного.


Як зазначалося в коментарі нижче @ThomasLeduc та інших, може виникнути проблема з реалізацією на основі регулярних виразів, якщо search містить певні символи, зарезервовані як спеціальні символи в регулярних виразах. Реалізація передбачає, що абонент заздалегідь вибере рядок або передасть лише рядки, які не містять символів у таблиці. Регулярні вирази (MDN).

MDN також забезпечує реалізацію, щоб уникнути наших рядків. Було б добре, якщо б це було також стандартизовано як RegExp.escape(str), але, на жаль, цього не існує:

function escapeRegExp(str) {
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
}

Ми могли б зателефонувати escapeRegExp в межах нашого String.prototype.replaceAll однак, я не знаю, скільки це вплине на продуктивність (потенційно навіть для рядків, для яких не потрібно втекти, як і всі буквено-цифрові рядки).


1635
2017-07-12 01:46



Чи можу я поцікавитись, що таке графічний символ для заміни всієї події струни? - jonney
У Android 4.1 метод регулярного виклику на 15% швидше, але ви не вислизнули з виразу для пошуку, тому цей еталон не є повним. - andreszs
Існує проблема з цим рішенням, якщо ви вказуєте, що пошуковий рядок містить спеціальні символи виразу regexp, вони будуть інтерпретовані. Я рекомендую відповідь @Sandy Unitedwolf. - Thomas Leduc
Перший зробить це: 'bla.bla'.replaceAll ('. ',' _ '); "_______". Другий виконає "bla_bla", що в цілому те, що ви хочете зробити. - RobKohr
Глянь над відповіддю. Переходьте до наступного, "неправильного" з міткою відповідей з 5 разів більше голосів. Це те, що ви хочете. - HoldOffHunger


str = str.replace(/abc/g, '');

У відповідь на коментар:

var find = 'abc';
var re = new RegExp(find, 'g');

str = str.replace(re, '');

У відповідь на Натисніть кнопку Upvote'S коментар, ви могли б спростити його ще більше:

function replaceAll(str, find, replace) {
    return str.replace(new RegExp(find, 'g'), replace);
}

Примітка: Регулярні вирази містять спеціальні (мета) символи, і тому небезпечно сліпо передавати аргумент у find функція вище без попередньої обробки його, щоб уникнути цих символів. Це покрито в Мережа розробників Mozillaс Довідник JavaScript щодо регулярних виразів, де вони представляють таку корисну функцію:

function escapeRegExp(str) {
    return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}

Так, щоб зробити replaceAll() Функція над безпечнішою, вона може бути змінена на наступне, якщо ви також включити escapeRegExp:

function replaceAll(str, find, replace) {
    return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}

3597
2017-07-17 17:54



Регулярні вирази є єдиним способом здійснення цього "поза вікна" без застосування власного методу "replaceAll". Я не пропоную їх використовувати лише ради їх використання. - Sean Bright
Це моя власна функція від цього коментарю: function replaceAll(find, replace,str) { var re = new RegExp(find, 'g'); str = str.replace(re, replace); return str; } - Click Upvote
Основна застереження Росії replaceAll реалізація полягає в тому, що вона не буде працювати, якщо find містить метасимволи. - Martin Ender
@ СеанБрайт, ти маєш рацію. Я використовував ваш JavaScript у коді PHP, тому мені довелося додати додаткову зворотну косу риску, щоб втекти. На скрипці ваш код ідеально підходить. Я повинен був перевірити. Вибачте jsfiddle.net/7y19xyq8 - Onimusha
@ Беннетт це погана практика розширення прототипу нативних типів JavaScript. - Emile Bergeron


Примітка. Не використовуйте це в реальному коді.

Як альтернативу регулярним виразам для простого буквенного рядка ви можете використовувати

str = "Test abc test test abc test...".split("abc").join("");

Загальна картина є

str.split(search).join(replacement)

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


1193
2017-07-17 20:29



Це мене здивувало, тому що я очікую, що цей метод буде виділяти більше об'єктів, створюючи більше сміття, і тим самим триватиме довше, але коли я фактично тестував у браузері, цей метод був постійно на 20% швидше, ніж прийнята відповідь. Результати можуть різнитися, звичайно. - MgSam
Мені було цікаво і налаштувати це: jsperf.com/replace-all-vs-split-join . Схоже, що v8 просто божевільний швидко розщеплення / об'єднання масивів в порівнянні з іншими движками javascript. - fabi
Дуже приємно - також заощаджує вас від можливої ​​помилки RegExps при проходженні в спеціальних символах. Я додаю в загальний прапор "знайти та замінити" в властивості об'єкта, але турбувався, чи потрібно мені замінити "." або "}" і забув я користувався RegEx через 3 місяці! - tobriand
На моєму ipad2 / сафарі спліт / приєднання на 65% повільніше, ніж заміна, тому результати можуть відрізнятися. - mrk
І як String.prototype: String.prototype.replaceAll = function(f,r){return this.split(f).join(r);}. Використання: "My string".replaceAll('st', ''); виробляє "моє кільце" - MacroMan


Використання регулярного виразу з g встановлений прапор замінить всі:

someString = 'the cat looks like a cat';
anotherString = someString.replace(/cat/g, 'dog');
// anotherString now contains "the dog looks like a dog"

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


507
2018-05-06 23:18



Я думаю, Kinda глупо, але JS global regex це єдиний спосіб зробити кілька заміни. - Mike
добре технічно ви можете цикл через var sourceText підрахуйте кількість випадків (numOfInstances) використовуючи substring або розділити і підрахувати довжину (серед інших стратегій) thatWhichYouWantToReplace потім робити for (var i = 0; i < numOfInstances; i++){ sourceText = sourceText.replace('thatWhichYouWantToReplace', ''); } або навіть простіше просто використовувати цикл while (while sourceText.indexOf(thatWhichYouWantToReplace > -1){ sourceText = sourceText.replace(...)), але я не розумію, чому ви хотіли б зробити це таким чином, коли використовуєте /g настільки легко і, мабуть, більш ефективно. - Zargold


Ось функція прототипу рядка на основі прийнятої відповіді:

String.prototype.replaceAll = function (find, replace) {
    var str = this;
    return str.replace(new RegExp(find, 'g'), replace);
};

РЕДАГУВАТИ 

Якщо ти find буде містити спеціальні символи, то вам потрібно буде уникнути їх:

String.prototype.replaceAll = function (find, replace) {
    var str = this;
    return str.replace(new RegExp(find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'), replace);
};

Скрипка: http://jsfiddle.net/cdbzL/


90
2018-02-11 23:03



Але що, якщо find містить такі символи, як . або $ які мають спеціальні значення в регулярному виразі? - callum
@callum У такому випадку вам доведеться уникнути вашої змінної пошуку (див. редагування вище). - jesal
Не змінюйте об'єкти, які ви не володієте - Aamir Afridi
Джесаль, це чудовий спосіб вирішення проблеми заміни рядка, який я зіткнувся, і, очевидно, долає "незмінність" рядків у JavaScript. Не могли б ви чи хтось інший пояснити, як ця функція прототипу перекриває незмінність струн? Це робить робота; Я просто хочу зрозуміти це допоміжне питання, яке він ставить. - Tom
@Том: це не робить подолати незмінність взагалі: var str = this створює другу посилання на незмінний рядок, до якого replace застосовується метод, який у свою чергу повертає a новий незмінний рядок. ці функції прототипу повертають нову незмінну рядок, якщо ні, то зможете написати someStrVar.replaceAll('o', '0'); і someStrVar буде змінено Замість цього вам потрібно написати someStrVar = someStrVar.replaceAll('o', '0'); <- перепризначити, щоб встановити вар, щоб тримати новий незмінний рядок. це неможливо. Спробуйте в консолі: x = 'foobar'; x.replaceAll('o', '0'); x; - Elias Van Ootegem


Оновлення:

Дещо запізнюватися на оновлення, але оскільки я просто наткнувся на це питання, і помітив, що моя попередня відповідь - це не той, яким я задоволений. Оскільки питання полягає у зміні одного слова, це незрозуміло, що ніхто не думав використовувати межі слів (\b)

'a cat is not a caterpillar'.replace(/\bcat\b/gi,'dog');
//"a dog is not a caterpillar"

Це простий регулярний вираз, який у більшості випадків уникає заміни частин слів. Однак тире - як і раніше вважається кордоном слова. Тому у цьому випадку можна використовувати умовні умови, щоб уникнути заміни рядків, як cool-cat:

'a cat is not a cool-cat'.replace(/\bcat\b/gi,'dog');//wrong
//"a dog is not a cool-dog" -- nips
'a cat is not a cool-cat'.replace(/(?:\b([^-]))cat(?:\b([^-]))/gi,'$1dog$2');
//"a dog is not a cool-cat"

в принципі, це питання схоже на питання тут: Javascript замінити "" з "" "

@Міке, перевірте відповідь, яку я там давав ... регулярний вираз - це не єдиний спосіб заміни кількох випадків підрядів, далеко не це. Подумайте про гнучкість, подумайте про розкол

var newText = "the cat looks like a cat".split('cat').join('dog');

Або ж, щоб запобігти заміненню частин слова - те, що також буде затверджена відповідь! Ви можете обійти цю проблему за допомогою регулярних виразів, які, як я визнаю, дещо складніші та як підсумок цього, трохи повільніше:

var regText = "the cat looks like a cat".replace(/(?:(^|[^a-z]))(([^a-z]*)(?=cat)cat)(?![a-z])/gi,"$1dog");

Вихід є таким самим, як прийнята відповідь, однак, використовуючи вираз / cat / g в цьому рядку:

var oops = 'the cat looks like a cat, not a caterpillar or coolcat'.replace(/cat/g,'dog');
//returns "the dog looks like a dog, not a dogerpillar or cooldog" ?? 

На жаль, це, мабуть, не те, що ви хочете. Що ж тоді? IMHO, регулярний вираз, який лише замінює 'cat' умовно. (тобто не частина слова), так:

var caterpillar = 'the cat looks like a cat, not a caterpillar or coolcat'.replace(/(?:(^|[^a-z]))(([^a-z]*)(?=cat)cat)(?![a-z])/gi,"$1dog");
//return "the dog looks like a dog, not a caterpillar or coolcat"

Я думаю, це відповідає вашим потребам. Звичайно, це не повноцінне, але воно повинно бути достатньо, щоб почати. Я рекомендую ознайомитись із цими сторінками. Це буде корисним у вдосконаленні цього виразу для задоволення ваших конкретних потреб.

http://www.javascriptkit.com/jsref/regexp.shtml

http://www.regular-expressions.info


Остаточне додавання:

Враховуючи, що це питання все ще отримує багато поглядів, я думав, що можу додати приклад .replace використовується з функцією зворотного виклику. У цьому випадку це різко спрощує вираз і забезпечує ще більшу гнучкість, наприклад, заміни правильної великої літери або заміну обох cat і cats в один раз:

'Two cats are not 1 Cat! They\'re just cool-cats, you caterpillar'
   .replace(/(^|.\b)(cat)(s?\b.|$)/gi,function(all,char1,cat,char2)
    {
       //check 1st, capitalize if required
       var replacement = (cat.charAt(0) === 'C' ? 'D' : 'd') + 'og';
       if (char1 === ' ' && char2 === 's')
       {//replace plurals, too
           cat = replacement + 's';
       }
       else
       {//do not replace if dashes are matched
           cat = char1 === '-' || char2 === '-' ? cat : replacement;
       }
       return char1 + cat + char2;//return replacement string
    });
//returns:
//Two dogs are not 1 Dog! They're just cool-cats, you caterpillar

75
2018-03-01 10:02



Я думаю, що додаткова цікава частина повинна бути розташована знизу. Пс .: Я зараз помітив, що половина першої лінії поза зоною, дозвольте мені дозволити це виправити!


Відповідність глобальному регулярному виразу:

anotherString = someString.replace(/cat/g, 'dog');

45
2018-05-06 23:23





str = str.replace(/abc/g, '');

Або спробуйте виконати функцію replaceAll тут:

Які корисні методи JavaScript, які розширюють вбудовані об'єкти?

str = str.replaceAll('abc', ''); OR

var search = 'abc';
str = str.replaceAll(search, '');

EDIT: Пояснення про доступність replaceAll

Метод 'replaceAll' доданий до прототипу String. Це означає, що він буде доступний для всіх рядкових об'єктів / літералів.

Наприклад,

var output = "test this".replaceAll('this', 'that');  //output is 'test that'.
output = output.replaceAll('that', 'this'); //output is 'test this'

35
2017-07-17 17:55



Чи можете ви перезаписати функцію replaceAll () для тих, хто не використовує прототип? - Click Upvote
@Click Upvote .... ви використовуєте прототип, це частина всіх об'єктів JS. Я думаю, ви думаєте про prototype.js бібліотеки JS. - seth
сет, трохи виправлення Якщо додати метод до прототипу, він доступний для всіх об'єктів цього типу. Метод replceAll був доданий до прототипу String, і він повинен працювати для всіх рядкових об'єктів. - SolutionYogi
@solutionyogi - Так, я раніше використовував прототип (правильно). Я просто звертався до коментаря О.П. про "не використовуючи прототип", який я мав на увазі як Prototype.js (можливо, неправильно?). Я повинен був сказати "прототип", оскільки я намагався сказати, що об'єкти JavaScript мають прототип. Таким чином, ОП вже "використовував прототип", хоча і "непрямим" способом. Непрямий може бути неправильним терміном для використання тут, але я втомився так mea culpa. - seth


Скажімо, ви хочете замінити всі 'abc' на 'x':

let some_str = 'abc def def lom abc abc def'.split('abc').join('x')
console.log(some_str) //x def def lom x x def

Я намагався думати про щось більш просто, ніж модифікувати прототип рядка.


29
2017-09-10 14:59



Простий, легкий і, мабуть, самий виразний варіант: гарна відповідь. - machineghost
Я не знаю, чи він ефективний, але .... це працює. - Emilio Grisolía
Насправді, хоча я не вимірював це особисто, спліт / приєднання зазвичай є дуже продуктивним рішенням. - machineghost
це навіть в Chrome, на 100% швидше в Firefox і на 50% повільніше в IE ...: jsperf.com/replace-regex-split-join - Olivier


Використовуйте регулярний вираз:

str.replace(/abc/g, '');

27
2017-07-17 17:56