String.prototype.replace()

Метод replace() (замінити) примірників String повертає новий рядок, в якому один, деякі чи всі збіги з переданим патерном заміщені переданою заміною. Патерн може бути рядком або регулярним виразом, а заміна може бути як рядком, так і функцією, яка буде викликана для кожного збігу. Якщо патерн — рядок, то заміняється лише перший збіг. Початковий рядок залишається незмінним.

Спробуйте його в дії

Синтаксис

replace(pattern, replacement)

Параметри

pattern (патерн)

Може бути рядком чи об'єктом, в котрого є метод Symbol.replace: типовим прикладом такого об'єкта є регулярний вираз. Будь-яке значення, котре не має метода Symbol.replace, буде приведене до рядка.

replacement (заміна)

Може бути рядком або функцією.

  • Якщо це рядок, то такий рядок замінить підрядок, що дав збіг з патерном. Підтримується низка особливих патернів заміни; дивіться розділ Передача рядка як заміни нижче.
  • Якщо це функція, то така функція буде викликана для кожного збігу, і повернене значення буде застосовано як текст заміни. Аргументи, що передаються такій функції, описані в розділі Передача функції як заміни нижче.

Повернене значення

Новий рядок, в якому один, деякі або всі збіги з патерном заміщені переданим замінником.

Опис

Цей метод не видозмінює рядкове значення, на котрому викликаний. Він повертає новий рядок.

Рядковий патерн замінюється лише раз. Аби виконати глобальний пошук із заміною, слід застосувати регулярний вираз із позначкою g або використати натомість replaceAll().

Якщо pattern є об'єктом із методом Symbol.replace (в т.ч. об'єктом RegExp), то такий метод викликається з цільовим рядком і replacement як аргументами. Його повернене значення стає поверненим значенням replace(). У такому випадку поведінка replace() цілком захована у методі @@replace: наприклад, будь-які згадки "груп захоплення" в описі нижче насправді є функціональністю, наданою RegExp.prototype[@@replace].

Якщо pattern є порожнім рядком, то заміна вставляється в початок вихідного рядка.

"xxx".replace("", "_"); // "_xxx"

Регулярний вираз із позначкою g є єдиним випадком, коли replace() виконує заміну більш ніж раз. Для отримання докладнішої інформації про те, як властивості регулярних виразів (особливо позначка липкості) взаємодіють з replace() дивіться RegExp.prototype[@@replace]().

Передача рядка як заміни

Рядок для заміни може містити наступні спеціальні патерни заміни:

Патерн Що вставляє
$$ Вставляє "$".
$& Вставляє підрядок, що дав збіг.
$` Вставляє частину рядка, що лежить перед підрядком, котрий дав збіг.
$' Вставляє частину рядка, що лежить після підрядка, котрий дав збіг.
$n Вставляє n-ту (з нумерацією від 1) групу захоплення, де n – додатне ціле число, менше за 100.
$<Name> Вставляє названу групу захоплення, де Name – ім'я групи.

$n і $<Name> доступні лише тоді, коли аргумент pattern є об'єктом RegExp. Якщо pattern є рядком, або ж якщо відповідна група захоплення не присутня в регулярному виразі, то патерн буде вставлений як є. Якщо група присутня, але не дала збігу (тому, що є частиною диз'юнкції), то вона буде вставлена як порожній рядок.

"foo".replace(/(f)/, "$2");
// "$2oo"; регулярний вираз не має другої групи

"foo".replace("f", "$1");
// "$1oo"; патерн є рядком, тож він не має жодних груп

"foo".replace(/(f)|(g)/, "$2");
// "oo"; друга група існує, але вона не дала жодного збігу

Передача функції як заміни

Другим аргументом можна також передати функцію. В цьому випадку функція викликається одразу, щойно збіг знайдено. Результат виконання функції (повернене значення) буде використано як рядок заміни.

Примітка: Згадані вище особливі патерни заміни не застосовуються для рядків, повернених з функції-замінювача.

Функція має наступну сигнатуру:

function replacer(match, p1, p2, /* …, */ pN, offset, string, groups) {
  return replacement;
}

Аргументи функції такі:

match (збіг)

Підрядок, що дав збіг. (Відповідає $& вище.)

p1, p2, …, pN

n-ний рядок, знайдений групою захоплення (включно з іменованими групами захоплення), за умови що перший аргумент replace() є об'єктом RegExp. (Відповідає $1, $2 тощо вище.). Наприклад, якщо pattern – це /(\a+)(\b+)/, то p1 – збіг для \a+, а p2 – збіг для \b+. Якщо група є частиною диз'юнкції (наприклад, "abc".replace(/(a)|(b)/, replacer)), то варіант, що не дав збігу, дасть undefined.

offset (відступ)

Відступ підрядка, що дав збіг, у межах всього досліджуваного рядка. Наприклад, якщо увесь рядок був 'abcd', а підрядок, що дав збіг, був 'bc', то цей аргумент буде 1.

string (рядок)

Увесь досліджуваний рядок.

groups (групи)

Об'єкт, чиї ключі – використовувані імена груп, і чиї значення – частини, що дали збіг (undefined, якщо збігу немає). Присутній лише тоді, коли pattern містить принаймні одну іменовану групу захоплення.

Конкретне число аргументів залежить від того, чи є перший аргумент об'єктом RegExp – і, якщо це так – того, скільки груп захоплення він має.

Наступний приклад присвоїть newString значення 'abc - 12345 - #$*%':

function replacer(match, p1, p2, p3, offset, string) {
  // p1 містить нецифрові символи, p2 — цифри, а p3 — все, окрім літер
  return [p1, p2, p3].join(" - ");
}
const newString = "abc12345#$*%".replace(/([^\d]*)(\d*)([^\w]*)/, replacer);
console.log(newString); // abc - 12345 - #$*%

Функція буде закликана декілька разів, для заміни кожного повного збігу, якщо регулярний вираз у першому параметрі є глобальним.

Приклади

Оголошення регулярного виразу безпосередньо в replace()

В наступному прикладі регулярний вираз оголошується всередині replace() і містить прапорець ігнорування регістру літер.

const str = "То була ніч перед Йолем...";
const newstr = str.replace(/йолем/i, "Різдвом");
console.log(newstr); // То була ніч перед Різдвом...

Це надрукує: 'То була ніч перед Різдвом...'.

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

Застосування з replace() позначок "глобальна заміна" та "знехтувати регістром"

Глобальна заміна може виконуватись лише із застосуванням регулярного виразу. В наступному прикладі регулярний вираз містить позначки "глобальний пошук" та "знехтувати регістром", що дає функції replace() змогу замінити всі входження 'яблука' на рядок з 'апельсини'.

const re = /яблука/gi;
const str = "Яблука — круглі, яблука — такі соковиті...";
const newstr = str.replace(re, "апельсини");
console.log(newstr); // апельсини — круглі, апельсини — такі соковиті...

Це надрукує: 'апельсини — круглі, апельсини — такі соковиті...'.

Обмін слів місцями в рядку

Наступний скрипт міняє слова місцями в рядку. Для отримання тексту заміни скрипт використовує групи захоплення і патерни заміни $1 та $2.

const re = /(\w+)\s(\w+)/;
const str = "Іван Сірко";
const newstr = str.replace(re, "$2, $1");
console.log(newstr); // Сірко, Іван

Це надрукує: 'Сірко, Іван'.

Застосування функції, оголошеної на місці, яка змінює літери збігу

В цьому прикладі всі наявні в рядку великі літери перетворюються в літери нижнього регістру, а перед місцем збігу вставляється дефіс. Важлива деталь: перед повернення рядка як рядка заміни над ним слід провести додаткові операції.

Функція заміни приймає своїм аргументом фрагмент, що збігся, і перед тим, як повернути його, використовує його для зміни регістру і приєднання дефіса.

function styleHyphenFormat(propertyName) {
  function upperToHyphenLower(match, offset, string) {
    return (offset > 0 ? "-" : "") + match.toLowerCase();
  }
  return propertyName.replace(/[A-Z]/g, upperToHyphenLower);
}

Для styleHyphenFormat('borderTop') це поверне 'border-top'.

Оскільки в цьому випадку потрібно додатково змінити знайдений збіг перед остаточною заміною, то слід вжити функцію. Це змушує програму спершу знайти збіг, тобто до виконання методу toLowerCase(). Якщо спробувати зробити заміну без функції, то метод toLowerCase() не матиме ефекту.

// так не працює
const newString = propertyName.replace(/[A-Z]/g, "-" + "$&".toLowerCase());

Так відбувається через те, що '$&'.toLowerCase() спочатку виконується як операція над рядком (повертаючи в результаті той самий рядок '$&'), до того, як спеціальне значення цих символів буде використано.

Заміна градусів за Фаренгейтом їхнім еквівалентом за шкалою Цельсія

Наступний приклад замінює градуси Фаренгейта їхнім еквівалентом в градусах Цельсія. Градуси Фаренгейта позначаються числом із літерою "F" в кінці. Функція повертає число градусів Цельсія зі літерою "C" в кінці. Наприклад, якщо вхідне число дорівнює "212F", функція поверне "100C". Якщо початкове число — "0F" – в результаті повернеться "-17.77777777777778C".

Регулярний вираз test шукає будь-яке число, після котрого стоїть літера F. Доступ функції до числа градусів по шкалі Фаренгейта здійснюється через її другий аргумент p1. Функція встановлює число градусів Цельсія на основі градусів Фаренгейта, переданих рядком до функції f2c(). Після цього f2c() повертає число градусів Цельсія. Ця функція працює приблизно як позначка s///e в Perl.

function f2c(x) {
  function convert(str, p1, offset, s) {
    return `${((p1 - 32) * 5) / 9}C`;
  }
  const s = String(x);
  const test = /(-?\d+(?:\.\d*)?)F\b/g;
  return s.replace(test, convert);
}

Створення узагальненого замінювача

Припустімо, що необхідно створити замінювач, що додає дані про відступ до кожного рядка, котрий дав збіг. У зв'язку з тим, що функція-замінювач отримує параметр offset, це буде тривіальним, якщо регулярний вираз статично відомий.

"abcd".replace(/(bc)/, (match, p1, offset) => `${match} (${offset}) `);
// "abc (1) d"

Проте такий замінювач буде важко узагальнити, якщо він повинен працювати з будь-яким патерном регулярного виразу. Замінювач є варіативним: число аргументів, котре він отримує, залежить від числа присутніх груп захоплення. Можна застосувати решту параметрів, але вона так само захопить у масив offset, string тощо. Факт того, що groups може бути або не бути переданим, залежно від ідентичності регулярного виразу, також ускладнює узагальнене з'ясування того, котрий з аргументів відповідає параметрові offset.

function addOffset(match, ...args) {
  const offset = args.at(-2);
  return `${match} (${offset}) `;
}
console.log("abcd".replace(/(bc)/, addOffset)); // "abc (1) d"
console.log("abcd".replace(/(?<group>bc)/, addOffset)); // "abc (abcd) d"

Приклад addOffset вище не спрацює, коли регулярний вираз містить іменовану групу, тому що в такому випадку args.at(-2) буде string, а не offset.

Замість цього необхідно дістати останні кілька аргументів на основі типу, адже groups є об'єктом, а string – рядком.

function addOffset(match, ...args) {
  const hasNamedGroups = typeof args.at(-1) === "object";
  const offset = hasNamedGroups ? args.at(-3) : args.at(-2);
  return `${match} (${offset}) `;
}
console.log("abcd".replace(/(bc)/, addOffset)); // "abc (1) d"
console.log("abcd".replace(/(?<group>bc)/, addOffset)); // "abc (1) d"

Специфікації

Сумісність із браузерами

desktop mobile server
Chrome Edge Firefox Internet Explorer Opera Safari WebView Android Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet Deno Node.js
replace
Chrome Full support 1
Edge Full support 12
Firefox Full support 1
Internet Explorer Full support 5.5
Opera Full support 4
Safari Full support 1
WebView Android Full support 1
Chrome Android Full support 18
Firefox for Android Full support 4
Opera Android Full support 10.1
Safari on iOS Full support 1
Samsung Internet Full support 1.0
Deno Full support 1.0
Node.js Full support 0.10.0

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