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

Регулярні вирази — це патерни, які застосовуються для пошуку збігів з комбінаціями символів у рядках. У JavaScript регулярні вирази також є об'єктами. Ці патерни використовуються методами об'єкта RegExp: exec() і test(), а також методами String: match(), matchAll(), replace(), replaceAll(), search() і split(). Цей розділ описує регулярні вирази у JavaScript.

Створення регулярного виразу

Сконструювати регулярний вираз можна одним із двох способів:

  • Використавши літерал регулярного виразу, який складається з патерну, оточеного скісними рисками, як показано нижче:

    const re = /ab+c/;
    

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

  • Або ж викликавши конструктор об'єкта RegExp, як показано:

    const re = new RegExp("ab+c");
    

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

Написання патерну регулярного виразу

Патерн регулярного виразу складається з простих символів, як от /abc/, або ж з поєднання простих і спеціальних символів, як /ab*c/ чи /Chapter (\d+)\.\d*/. Останній приклад містить дужки, які використовуються як вказівка до запам'ятовування. Зіставлення, виконане з цією частиною патерну, буде запам'ятоване для пізнішого використання, як це описано в частині Застосування груп.

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

Застосування простих патернів

Прості патерни складаються з символів, яким треба знайти прямі відповідники. Наприклад, патерн /abc/ збігається з комбінацією символів у рядках тільки коли трапляється саме ця послідовність – "abc" (всі букви разом, і саме в такому порядку). Такий збіг трапився б у двох рядках: "Hi, do you know your abc's?" і "The latest airplane designs evolved from slabcraft.". В обох випадках трапляється збіг з підрядком "abc". Не існує збігів у рядку "Grab crab", і хоча він містить підрядок "ab c", в ньому не зустрічається точна послідовність "abc".

Застосування спеціальних символів

Якщо пошук збігу потребує чогось більшого, аніж просто прямого відповідника, як от знаходження однієї чи більше літер «b», чи знаходження пробілу, слід включати в патерн спеціальні символи. Наприклад, щоб знайти збіг для одної літери "a", після якої є нуль або більше літер "b", а за ними літера "c", використовується патерн /ab*c/: зірочка * після "b" означає "наявність попереднього елемента в кількості 0 чи більше одиниць. В рядку "cbbabbbbcdebc" цей патерн покаже збіг з підрядком "abbbbc".

Наступні сторінки містять списки різних спеціальних символів, розбитих на категорії, з описами та прикладами.

Посібник Перевірки

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

Посібник Класи символів

Розрізняють різні типи символів. Наприклад, розрізнення літер та цифр.

Посібник Групи й зворотні посилання

Групи групують декілька патернів як єдине ціле, а групи захоплення надають додаткову інформацію вкладеного збігу, коли патерн регулярного виразу зіставляється з рядком. Зворотні посилання посилаються на попередньо захоплену групу в тому самому регулярному виразі.

Посібник Квантори

Вказують кількість символів чи виразів для збігу.

Нижче наведено єдину таблицю всіх спеціальних символів, які можна використовувати в регулярних виразах:

Спеціальні символи в регулярних виразах.
Символи / конструкції Відповідна стаття
[xyz], [^xyz], ., \d, \D, \w, \W, \s, \S, \t, \r, \n, \v, \f, [\b], \0, \cX, \xhh, \uhhhh, \u{hhhh}, x|y

Класи символів

^, $, \b, \B, x(?=y), x(?!y), (?<=y)x, (?<!y)x

Перевірки

(x), (?<Name>x), (?:x), \n, \k<Name>

Групи та зворотні посилання

x*, x+, x?, x{n}, x{n,}, x{n,m}

Квантори

Примітка: Доступна також більша шпаргалка (що містить лише витяги зі статей окремих спецсимволів).

Екранування

Якщо потрібно вжити будь-який спеціальний вираз буквально (наприклад, шукаючи власне символ "*"), його потрібно екранувати шляхом додавання зворотного скосу перед ним. Зокрема, щоб знайти літеру "a", за якою слідує "*", слідом за яким літера "b", треба вжити патерн /a\*b/: зворотний скіс «екранує» "*", роблячи її просто знаком і нейтралізуючи спеціальне значення.

Аналогічно, якщо під час написання літерала регулярного виразу потрібно знайти збіг із символом скосу ("/"), слід його екранувати (інакше він означатиме кінець патерну). Для прикладу, щоб знайти рядок "/example/", за яким слідує одна чи більше букв алфавіту, слід використати патерн /\/example\/[a-z]+/i — зворотна коса перед кожною косою робить їх просто символами.

Щоб знайти збіг зворотного скосу буквально, слід його екранувати. Наприклад, щоб знайти рядок "C:\", де «C» може бути будь-якою літерою, слід використати патерн /[A-Z]:\\/: перший зворотний скіс екранує наступний після нього, тож вираз шукатиме буквально одну зворотну скісну риску.

Використовуючи конструктор RegExp з рядковим літералом, пам'ятайте, що зворотний скіс — це екранувальний символ в рядкових літералах. І щоб застосувати його в регулярному виразі, слід спершу його екранувати на рівні рядкового літерала. /a\*b/ та new RegExp("a\\*b") створюють один і той самий вираз, який шукатиме літеру "a" з символом за нею "*" і літерою "b" після них.

Якщо екранувальні рядки ще не входять в готовий патерн, їх можна додати за допомогою String.prototype.replace():

function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& означає цілий рядок, який збігся з патерном
}

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

Чому це не вбудовано всередину JavaScript? Існує пропозиція додати таку функцію до RegExp.

Застосування дужок

Дужки навколо будь-якої частини патерну регулярного виразу призводять до того, що ця частина знайденого підрядка буде збережена окремо. До збереженого підрядка можна потім знову звернутися і використати для інших цілей. Більше деталей є в розділі Групи та зворотні посилання.

Застосування регулярних виразів у JavaScript

Регулярні вирази з методами об'єкта RegExp, наприклад, test() і exec(), а також із методами String: match(), matchAll(), replace(), replaceAll(), search() і split().

Метод Опис
exec() Виконує пошук збігу в рядку. Повертає масив з інформацією або null, якщо збігів не знайдено.
test() Перевіряє рядок на збіг. Повертає true або false.
match() Повертає масив, що містить всі знайдені збіги, включно з групами захоплення, або ж null, якщо збігів не знайдено.
matchAll() Повертає ітератор, що містить всі знайдені збіги, включно з групами захоплення.
search() Перевіряє рядок на наявність збігів. Повертає індекс збігу, або -1, якщо пошук завершився невдачею.
replace() Виконує пошук збігу в рядку і заміняє знайдену частину рядка переданим рядком для заміни.
replaceAll() Виконує пошук всіх збігів у рядку і заміняє знайдені частини рядка переданим рядком для заміни.
split() Використовує регулярний вираз або фіксований рядок, щоб розбити початковий рядок на масив підрядків.

Якщо потрібно визначити, чи патерн присутній в рядку, використовуйте методи test() або search(). Для отримання докладнішої інформації (вкупі з повільнішим виконанням) застосовуйте методи exec() чи match(). Якщо використовується метод exec() чи match(), і знаходиться збіг, ці методи повертають масив і оновлюють властивості пов'язаного об'єкта регулярного виразу, а також властивості глобального об'єкта RegExp. Якщо збіг знайти не вдалося, то метод exec() поверне null (який, зрештою, зводиться до false).

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

const myRe = /d(b+)d/g;
const myArray = myRe.exec("cdbbdbsbz");

А в цьому сценарії — альтернативний варіант створення масиву myArray, на випадок якщо вам не потрібен доступ до властивостей самого регулярного виразу:

const myArray = /d(b+)d/g.exec("cdbbdbsbz");
// так само, як і з "cdbbdbsbz".match(/d(b+)d/g); однак,
// "cdbbdbsbz".match(/d(b+)d/g) виводить [ "dbbd" ]
// /d(b+)d/g.exec('cdbbdbsbz') виводить [ 'dbbd', 'bb', index: 1, input: 'cdbbdbsbz' ]

(Дивіться більше інформації цю різницю в поведінці у частині Застосування позначки глобального пошуку з exec().)

Якщо ж потрібно сконструювати регулярний вираз із рядка, ось іще одна альтернатива:

const myRe = new RegExp("d(b+)d", "g");
const myArray = myRe.exec("cdbbdbsbz");

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

Результати виконання регулярних виразів.
Об'єкт Властивість або індекс Опис В цьому прикладі
myArray Рядок, що збігся, а також всі запам'ятовані підрядки. ['dbbd', 'bb', index: 1, input: 'cdbbdbsbz']
index Індекс позиції (від 0) збігу у вхідному рядку. 1
input Вхідний рядок. 'cdbbdbsbz'
[0] Символи з останнього збігу. 'dbbd'
myRe lastIndex Індекс, з якого почнеться пошук наступного збігу. (Ця властивість встановлюється лише якщо регулярний вираз використовує опцію «g», описану в частині Поглиблений пошук з позначками.) 5
source Текст патерну. Оновлюється в момент створення регулярного виразу, не виконання. 'd(b+)d'

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

const myRe = /d(b+)d/g;
const myArray = myRe.exec("cdbbdbsbz");
console.log("Поле lastIndex має значення " + myRe.lastIndex);

// "Поле lastIndex має значення 5"

Однак, якщо натомість у нас є такий сценарій:

const myArray = /d(b+)d/g.exec("cdbbdbsbz");
console.log("Поле lastIndex має значення " + /d(b+)d/g.lastIndex);

// "Поле lastIndex має значення 0"

Вирази /d(b+)d/g у двох інструкціях вище — це насправді різні об'єкти регулярного виразу, і тому вони містять різні значення їхньої властивості lastIndex. Якщо потрібно доступитися до властивостей регулярного виразу, створеного об'єктним конструктором, слід спершу присвоїти його змінній.

Поглиблений пошук з позначками

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

Позначка Опис Відповідна властивість
d Згенерувати індекси для збігів підрядків. hasIndices
g Глобальний пошук. global
i Пошук, нечутливий до регістру. ignoreCase
m Дозволяє ^ та $ давати збіг поруч з символами нового рядка. multiline
s Дозволяє символові . давати збіг з символами нового рядка. dotAll
u "Unicode"; сприймає патерн як послідовність кодових точок Unicode. unicode
v Оновлена версія режиму u, з більшою кількістю можливостей Unicode. unicodeSets
y Виконує «липкий» пошук, який починає пошук збігів з поточної позиції цільового рядка. sticky

Щоб включити позначку в регулярний вираз, використовується такий синтаксис:

const re = /pattern/flags;

або

const re = new RegExp("pattern", "flags");

Зауважте, що ці опції — це невідокремна частина регулярного виразу. Їх неможливо додати чи прибрати потім.

Наприклад, re = /\w+\s/g створює регулярний вираз, що шукає одну або більше літер, за якими слідує пробіл, і він виконує цей пошук по всьому рядку.

const re = /\w+\s/g;
const str = "fee fi fo fum";
const myArray = str.match(re);
console.log(myArray);

// ["fee ", "fi ", "fo "]

Можна замінити цей рядок:

const re = /\w+\s/g;

...на такий:

const re = new RegExp("\\w+\\s", "g");

...і отримати такий самий результат.

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

Застосування позначки глобального пошуку з exec()

Метод RegExp.prototype.exec() із позначкою g ітеративно поверне кожен збіг та його позицію.

const str = "fee fi fo fum";
const re = /\w+\s/g;
console.log(re.exec(str)); // ["fee ", index: 0, input: "fee fi fo fum"]
console.log(re.exec(str)); // ["fi ", index: 4, input: "fee fi fo fum"]
console.log(re.exec(str)); // ["fo ", index: 7, input: "fee fi fo fum"]
console.log(re.exec(str)); // null

Натомість метод String.prototype.match() поверне усі збіги відразу, втім, без їх позицій.

console.log(str.match(re)); // ["fee ", "fi ", "fo "]

Використання юнікодних регулярних виразів

Прапорець "u" використовується для створення "юнікодних" регулярних виразів; це такі регулярні вирази, котрі підтримують пошук збігів у юнікодному тексті. Це здебільшого досягнуто шляхом використання екранування юнікодних властивостей. Наприклад, наступний регулярний вираз може застосовуватися для пошуку збігу в довільному юнікодному "слові":

/\p{L}*/u;

Регулярні вирази Unicode також мають інакшу логіку виконання. Стаття RegExp.prototype.unicode містить подробиці на цю тему.

Приклади

Примітка: Декілька прикладів також доступні:

Застосування спеціальних символів для перевірки вводу

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

Регулярний вираз шукає:

  1. Початок рядка з даними: ^
  2. Далі три цифрових знаки \d{3} АБО | ліва дужка \( з трьома цифрами за нею \d{3}, закритими правою дужкою \), і це все об'єднано в групу (без захоплення) (?:)
  3. Далі один дефіс, скісна риска або десяткова крапка, що захоплено в групу ()
  4. Далі іще три цифри \d{3}
  5. Далі збіг, запам'ятований у першій захопленій групі \1
  6. Далі іще чотири цифри \d{4}
  7. І за ними кінець рядка з даними: $

Подія click, котра спрацьовує під час натискання користувачем клавіші Enter, встановлює значення phoneInput.value.

HTML

<p>
  Введіть ваш номер телефону (з кодом населеного пункту) та натисність
  "Перевірити".
  <br />
  Очікуваний формат номера: ###-###-####.
</p>
<form id="form">
  <input id="phone" />
  <button type="submit">Перевірити</button>
</form>
<p id="output"></p>

JavaScript

const form = document.querySelector("#form");
const input = document.querySelector("#phone");
const output = document.querySelector("#output");

const re = /^(?:\d{3}|\(\d{3}\))([-/.])\d{3}\1\d{4}$/;

function testInfo(phoneInput) {
  const ok = re.exec(phoneInput.value);
  output.textContent = ok
    ? `Дякую, ваш номер телефону – ${ok[0]}`
    : `${phoneInput.value} не є телефонним номером із кодом населеного пункту!`;
}
form.addEventListener("submit", (event) => {
  event.preventDefault();
  testInfo(input);
});

Результат

Інструменти

RegExr

Онлайн-інструмент для вивчення, побудови та тестування регулярних виразів.

Regex tester

Онлайн-інструмент для побудови та зневадження регулярних виразів

Regex interactive tutorial

Онлайнові інтерактивні підручники, шпаргалка та ігровий майданчик.

Regex visualizer

Візуальний онлайн-інструмент для тестування регулярних виразів.