Декільки символів, або класи символів всередині квадратних дужок […] означають “шукати будь-який символ з-поміж заданих”.
Набори
До прикладу, [eao] означає будь-який з трьох символів: 'a', 'e', or 'o'.
У такий спосіб записується так званий набір. Набір може використовуватись в регулярних виразах разом зі звичайними символами:
// знайти [t або m], а потім "op"
alert( "Mop top".match(/[tm]op/gi) ); // "Mop", "top"
Зверніть увагу, що незважаючи на те, що в наборі вказано два символи, в результаті є співпадіння лише по одному з них.
Тож нижченаведений приклад не знайде співпадінь:
// знайти "V", потім [o чи i], потім "la"
alert( "Voila".match(/V[oi]la/) ); // null, співпадінь не знайдено
Шаблон шукає:
V,- потім одна з літер набору
[oi], - потім
la.
Результатом такого пошуку могли б стати варіанти Vola або Vila.
Діапазони
Квадратні дужки також можуть містити діапазони символів.
До прикладу, [a-z] шукатиме символу в діапазоні від a до z, а [0-5] дорівнює цифрам в діапазоні від 0 до 5.
В нижченаведеному прикладі ми шукатимемо літеру "x" за якою ідуть дві цифри, або літери від A до F:
alert( "Exception 0xAF".match(/x[0-9A-F][0-9A-F]/g) ); // xAF
Тут [0-9A-F] має в собі одразу два діапазони: він шукає символ, який є або цифрою від 0 до 9, або літерою від A до F.
Якби ми захотіли шукати літери не тільки верхнього, а й нижнього регістру, ми могли б додати діапазон a-f: [0-9A-Fa-f]. Або додати флаг i.
Крім того, всередині […] ми можемо використовувати символьні класи.
До прикладу, якщо ми захочемо знайти символ “слова” \w , або дефіс -, набір виглядатиме наступним чином [\w-].
Комбінувати декілька класів теж можливо, наприклад [\s\d] означає “пробіл, або цифра”.
До прикладу:
- \d – те саме, що й
[0-9], - \w – те саме, що й
[a-zA-Z0-9_], - \s – те саме, що й
[\t\n\v\f\r ], плюс декілька інших рідкісних пробільних символів Unicode.
Приклад: \w в інших мовах світу
Оскільки символьний клас \w це лише скорочений запис [a-zA-Z0-9_], він не зможе знайти китайські ієрогліфи, літери кирилицею тощо.
Існує спосіб написати більш універсальний шаблон, що включатиме в себе буквенні символи будь-якої мови світу. Це легко реалізувати завдяки властивостям Unicode: [\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}].
Давайте розшифруємо цей шаблон. Подібно до \w, ми створюємо свій діапазон, який включає в себе символи з наступними властивостями Unicode:
Alphabetic(Alpha) – для літер,Mark(M) – для акцентів,Decimal_Number(Nd) – для цифр,Connector_Punctuation(Pc) – для нижнього підкреслення'_'і подібних символів,Join_Control(Join_C) – два спеціальних коди200cта200d, які використовуються у лігатурах, зокрема в арабській мові.
Шаблон в дії:
let regexp = /[\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}]/gu;
let str = `Hi 你好 12`;
// знайти всі літери та цифри:
alert( str.match(regexp) ); // H,i,你,好,1,2
Звичайно, ми можемо редагувати вищенаведений шаблон: додавати Unicode властивості, або видаляти їх. Дізнатись більше про Unicode властивості можна за посиланням Юнікод: прапорець "u" та клас \p{...}.
Unicode властивості p{…} недоступні у Internet Explorer. Втім, якщо вони нам все ж потрібні, ми можемо скористатись бібліотекою XRegExp.
Або просто вказати діапазон потрібних нам символів з необхідної мови, наприклад [а-я] для літер кирилицею.
Діапазони виключень
Окрім звичайних діапазонів, існують діапазони “виключень” які виглядають наступним чином: [^…].
Вони відрізняються символом каретки ^ на початку і знаходять будь-який символ окрім вказаних в діапазоні.
До прикладу:
[^aeyo]– будь-який символ окрім'a','e','y'or'o'.[^0-9]– будь-який символ окрім цифр, так само як і\D.[^\s]– будь-який не пробільний символ\S.
Нижченаведений приклад шукає будь-який символ окрім літер латиницею, цифр та пробільних символів:
alert( "alice15@gmail.com".match(/[^\d\sA-Z]/gi) ); // @ та .
Екранування всередині […]
Зазвичай, коли ми хочемо знайти один зі спецсимволів, нам потрібно екранувати його наступним чином \.. Тобто, якщо нам потрібна зворотня коса риска, ми маємо писати \\, і так далі.
В квадратних дужках ми можемо використовувати велику кількість спецсимволів без екранування:
- Символ
. + ( )не потребує екранування. - Дефіс
-не потребує екранування на початку, або в кінці (тобто коли не може означати діапазон). - Каретка
^екранується лише на початку (без екранування означає набір символів-виключень). - Закриваюча квадратна дужка
]завжди потребує екранування (у випадках, коли нам потрібно знайти цей символ).
Інакше кажучи, всі спецсимволи можна використовувати без екранування тоді, коли вони не мають додаткового значення в квадратних дужках.
Крапка . всередині квадратних дужок означає просто крапку. Шаблон [.,] шукатиме один з двох символів, або крапку, або кому.
В нижченаведеному прикладі регулярний вираз [-().^+] шукає один з вказаних символів -().^+:
// Не потрібно екранувати
let regexp = /[-().^+]/g;
alert( "1 + 2 - 3".match(regexp) ); // Знаходить +, -
…Але якщо ви вирішите все ж таки екранувати їх, “про всяк випадок”, гірше від того не буде:
// Всі символи екрановані
let regexp = /[\-\(\)\.\^\+]/g;
alert( "1 + 2 - 3".match(regexp) ); // так само находить: +, -
Діапазони і прапорець “u”
Якщо в діапазоні є сурогатні пари, для коректної роботи регулярного виразу, прапорець u є обов’язковим.
До прикладу, давайте знайдемо [𝒳𝒴] у рядку 𝒳:
alert( '𝒳'.match(/[𝒳𝒴]/) ); // виводить дивний символ, схожий на [?]
// (пошук було виконано некореткно, повернуто тільки половину символу)
Результат є некоректним, оскільки типово регулярні вирази “не знають” про сурогатні пари.
Регулярний вираз сприймає [𝒳𝒴] – не як два, а як чотири символи:
- ліва половина
𝒳(1), - права половина
𝒳(2), - ліва половина
𝒴(3), - права половина
𝒴(4).
Якщо вивести їх кодове значення ми побачимо наступне:
for(let i=0; i<'𝒳𝒴'.length; i++) {
alert('𝒳𝒴'.charCodeAt(i)); // 55349, 56499, 55349, 56500
};
Отже, вищенаведений приклад знайшов і вивів ліву половину 𝒳.
Якщо ми додамо прапорець u, то поведінка буде коректною:
alert( '𝒳'.match(/[𝒳𝒴]/u) ); // 𝒳
Подібна ситуація складається коли ми шукаємо в діапазоні, наприклад [𝒳-𝒴].
Якщо ми забудемо додати прапорець u, то отримаємо помилку:
'𝒳'.match(/[𝒳-𝒴]/); // Error: Invalid regular expression
Причина в тому, що без прапорцю u сурогатні пари сприймаються як два окремих символи, тобто [𝒳-𝒴] обробляються як [<55349><56499>-<55349><56500>] (кожна сурогатна пара замінюється на набір кодів). Таким чином, ми бачимо, що діапазон 56499-55349 є некоректним: його початковий номер 56499 більший за останній 55349. Це і є причиною помилки.
З прапорцем u шаблон працює коректно:
// шукає символи від 𝒳 до 𝒵
alert( '𝒴'.match(/[𝒳-𝒵]/u) ); // 𝒴
Коментарі
<code>, для кількох рядків – обгорніть їх тегом<pre>, для понад 10 рядків – використовуйте пісочницю (plnkr, jsbin, codepen…)