Як ми бачили, бекслеш \
використовується для позначення класів символів, напр. \d
. Це спеціальний символ у регулярних виразах (як і у звичайних рядках).
Існують також інші спеціальні символи, які мають особливе значення в регулярних виразах, наприклад [ ] { } ( ) \ ^ $ . | ? * +
. Вони використовуються, щоб посилити можливості пошуку.
Не намагайтеся запам’ятати список – незабаром ми розберемо кожен з них окремо, і ви їх легко запам’ятаєте.
Екранування
Скажімо, ми хочемо знайти саме крапку. Не “будь-який символ”, а просто крапку.
Щоб використовувати спеціальний символ як звичайний, додайте перед ним бекслеш: \.
.
Це також називається “екранування символу”.
Наприклад:
alert( "Chapter 5.1".match(/\d\.\d/) ); // 5.1 (співпадіння!)
alert( "Chapter 511".match(/\d\.\d/) ); // null (шукаємо справжню крапку \.)
Дужки також є спеціальними символами, тому, якщо нам потрібно їх знайти, ми повинні використовувати \(
. У прикладі нижче шукаємо рядок "g()"
:
alert( "function g()".match(/g\(\)/) ); // "g()"
Якщо ми шукаємо бекслеш \
, як ви пам’ятаєте, це спеціальний символ як у звичайних рядках, так і в регулярних виразах, ми повинні подвоїти його (екранувати).
alert( "1\\2".match(/\\/) ); // '\'
Слеш
Символ слешу '/'
не є спеціальним символом, але в JavaScript він використовується для відкриття та закриття регулярного виразу: /...pattern.../
, тому ми також повинні екранувати його.
Ось як виглядає пошук слешу '/'
:
alert( "/".match(/\//) ); // '/'
З іншого боку, якщо ми не використовуємо /.../
, а створюємо регулярний вираз за допомогою new RegExp
, тоді нам не потрібно його екранувати:
alert( "/".match(new RegExp("/")) ); // знаходить /
new RegExp
Якщо ми створюємо регулярний вираз за допомогою new RegExp
, тоді нам не потрібно екранувати /
, але потрібно зробити інше екранування.
Наприклад, розглянемо наступний код:
let regexp = new RegExp("\d\.\d");
alert( "Chapter 5.1".match(regexp) ); // null
Подібний пошук в одному з попередніх прикладів працював із /\d\.\d/
, але new RegExp("\d\.\d")
не працює, чому?
Причина полягає в тому, що рядок “поглинає” бекслеши. Як ми можемо пам’ятати, звичайні рядки мають власні спеціальні символи, такі як \n
, а бекслеш використовується для їх екранування.
Ось як сприймається “\d.\d”:
alert("\d\.\d"); // d.d
Рядкові лапки “поглинають” зворотні слеши та інтерпретують їх самостійно, наприклад:
\n
– стає символом нового рядка,\u1234
– стає символом Unicode з таким кодом,- …А коли немає особливого значення: як-от
\d
або\z
, тоді бекслеш просто видаляється.
Тому new RegExp
отримує рядок без бекслешів, і пошук не працює!
Щоб це виправити, нам потрібно подвоїти бекслеши, оскільки лапки рядка автоматично перетворюють \\
на \
:
let regStr = "\\d\\.\\d";
alert(regStr); // \d\.\d (тепер правильно)
let regexp = new RegExp(regStr);
alert( "Chapter 5.1".match(regexp) ); // 5.1
Підсумки
- Для пошуку спеціальних символів
[ \ ^ $ . | ? * + ( )
, нам потрібно додати перед ними\
(“екранувати їх”). - Нам також потрібно екранувати
/
, якщо ми знаходимося всередині/.../
(але не всерединіnew RegExp
). - При передачі рядка в
new RegExp
, нам необхідно подвоїти бекслеши\\
, тому що лапки рядка поглинають один з них.