24 лютого 2024 р.

Вступ: шаблони та прапори

Регулярні вирази – потужний засіб пошуку та заміни тексту в рядках.

В JavaScript регулярні вирази реалізовані окремим об’єктом RegExp та інтегровані у методи рядків.

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

Регулярний вираз (він же “регексп”, “регулярка” або просто “рег”), складається з шаблону (також кажуть “патерн”) і необов’язкових прапорів.

Існує два синтаксиси для створення регулярного виразу.

“Довгий” синтаксис:

regexp = new RegExp("шаблон", "прапори");

Та “короткий” синтаксис, в якому використовуються слеши "/":

regexp = /шаблон/; // без прапорів
regexp = /шаблон/gmi; // з прапорами g,m та i (будуть описані далі)

Слеши /.../ говорять JavaScript про те, що це регулярний вираз. Вони відіграють таку саму роль, як і лапки для позначення рядків.

Регулярний вираз regexp в обох випадках є об’єктом вбудованого класу RegExp.

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

Слеши використовуються, коли ми на момент написання коду точно знаємо, яким буде регулярний вираз – і це більшість ситуацій. А new RegExp – коли ми хочемо створити регулярний вираз “на льоту” з динамічно згенерованого рядка, наприклад:

let tag = prompt("Який тег ви хочете знайти?", "h2");

let regexp = new RegExp(`<${tag}>`); // те саме, що /<h2>/ при відповіді "h2" на запит вище

Прапори

Регулярні вирази можуть мати прапори, які впливають на пошук.

У JavaScript їх всього шість:

i
З цим прапором пошук не залежить від регістру: немає різниці між A та a (див. приклад нижче).
g
З цим прапором пошук шукає всі збіги, без нього – лише перше.
m
Багаторядковий режим (розглядається в розділі Багаторядковий режим якорів ^ $, прапора "m").
s
Вмикає режим “dotall”, при якому крапка . може відповідати символу нового рядка \n (розглядається у розділі Символьні класи).
u
Вмикає повну підтримку Юнікоду. Прапор дозволяє коректну обробку сурогатних пар (докладніше про це у розділі Юнікод: прапорець "u" та клас \p{...}).
y
Режим пошуку на конкретній позиції в тексті (описаний у розділі Липкий прапорець "y", пошук на заданій позиції)
Кольорові позначення

Тут і далі в тексті використовується наступна колірна схема:

  • регулярний вираз – червоний
  • рядок (там, де відбувається пошук) – синій
  • результат – зелений

Пошук: str.match

Як вже згадувалося, використання регулярних виразів інтегровано у методи рядків.

Метод str.match(regexp) для рядка str повертає збіги з регулярним виразом regexp.

У нього є три режими роботи:

  1. Якщо в регулярного виразу є прапор g, то він повертає масив всіх збігів:

    let str = "За Вас правда, за вас слава і воля святая!";
    alert(str.match(/вас/gi)); // Вас, вас (масив із 2х підрядків-збігів)

    Зверніть увагу: знайдено як Вас так і вас, завдяки прапору i, який робить регулярний вираз реєстронезалежним.

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

    let str = "За Вас правда, за вас слава і воля святая!";
    
    let result = str.match(/вас/i); // без прапора g
    
    alert(result[0]); // Вас (перший збіг)
    alert(result.length); // 1
    
    // Додаткова інформація:
    alert(result.index); // 0 (позиція збігу)
    alert(result.input); // За Вас правда, за вас слава і воля святая! (вихідний рядок)

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

  3. І, нарешті, якщо збігів немає, то, незалежно від наявності прапора g, повертається null.

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

    let matches = "JavaScript". match(/HTML/); // = null
    if (!matches.length) { // Помилка: у null немає властивості length
      alert("Помилка у рядку вище");
    }

    Якщо хочеться, щоб результатом завжди був масив, можна написати так:

    let matches = "JavaScript".match(/HTML/) || [];
    if (!matches.length) {
      alert("Збігів немає"); // тепер працює
    }

Заміна: str.replace

Метод str.replace(regexp, replacement) замінює збіги з regexp у рядку str на replacement (всі збіги, якщо є прапор g, інакше тільки перше).

Наприклад:

// без прапора g
alert( "Ми будемо, ми будемо".replace(/ми/i, "Я") ); // Я будемо, ми будемо

// з прапором g
alert( "Ми будемо, ми будемо".replace(/ми/ig, "Я") ); // Я будемо, Я будемо

У рядку заміни replacement ми можемо використовувати спеціальні комбінації символів для вставки фрагментів збігу:

Спецсимволи Дія у рядку заміни
$& вставляє всі знайдені збіги
$` вставляє частину рядка до збігу
$' вставляє частину рядка після збігу
$n якщо n це 1-2 значне число, вставляє вміст n-ї скобочної групи регулярного виразу, більше у розділі Групи захоплення
$<name> вставляє вміст скобочної групи з ім’ям name, також вивчимо у розділі Групи захоплення
$$ вставляє символ "$"

Приклад з $&:

alert( "Люблю HTML".replace(/HTML/, "$& і JavaScript") ); // Люблю HTML і JavaScript

Перевірка: regexp.test

Метод regexp.test(str) перевіряє, чи є хоч один збіг, якщо так, то повертає true, інакше false.

let str = "Я люблю JavaScript";
let regexp = /люблю/i;

alert( regexp.test(str) ); // true

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

Повна інформація про різні методи наведена в розділі Методи регулярних виразів та рядків.

Підсумки

  • Регулярний вираз складається з шаблону і необов’язкових прапорів: g, i, m, u, s, y.
  • Без прапорів та спеціальних символів, які ми вивчимо пізніше, пошук за регулярним виразом аналогічний пошуку підрядка.
  • Метод str.match(regexp) шукає збіги: всі, якщо є прапор g, інакше тільки перший.
  • Метод str.replace(regexp, replacement) замінює збіги з regexp на replacement: всі, якщо у регулярного виразу є прапор g, інакше тільки перший.
  • Метод regexp.test(str) повертає true, якщо є хоч один збіг, інакше false.
Навчальна карта

Коментарі

прочитайте це, перш ніж коментувати…
  • Якщо у вас є пропозиції, щодо покращення підручника, будь ласка, створіть обговорення на GitHub або одразу створіть запит на злиття зі змінами.
  • Якщо ви не можете зрозуміти щось у статті, спробуйте покращити її, будь ласка.
  • Щоб вставити код, використовуйте тег <code>, для кількох рядків – обгорніть їх тегом <pre>, для понад 10 рядків – використовуйте пісочницю (plnkr, jsbin, codepen…)