4 січня 2023 р.

Квантифікатори +, *, ? та {n}

Припустимо, у нас є рядок +38(067)-123-45-67 і нам потрібно знайти всі числа в ньому. Але цього разу, на відміну від попередніх, нас цікавлять не поодинокі цифри, а саме числа : 38, 067, 123, 45, 67.

Число це послідовність з 1, або більше цифр \d і щоб позначити потрібну нам кількість, ми можемо застосувати квантифікатор.

Кількість {n}

Найпростішим квантифікатором є число у фігурних дужках: {n}.

Квантифікатор додається до символу(або класу символів, набору [...], тощо) і позначає яка їх кількість нам потрібна.

Існує декілька способів використання квантифікатора, розглянемо на прикладах:

Точна кількість: {5}

\d{5} означає точно 5 цифр, так само як і \d\d\d\d\d.

Нижченаведений приклад шукатиме число, яке складається з 5-ти цифр:

alert( "Мені 12345 років".match(/\d{5}/) ); //  "12345"

Ми могли б додати \b і таким чином вилучити з пошуку числа довші за наш шаблон: \b\d{5}\b.

Діапазон: {3,5}, від 3 до 5

Щоб знайти числа, які складаються з мінімум 3 і максимум 5 чисел, ми можемо вказати потрібні обмеження у фігурних дужках: \d{3,5}

alert( "Мені не 12 років, а 1234".match(/\d{3,5}/) ); // "1234"

Ми можемо не вказувати верхню межу.

В такому випадку, регулярний вираз \d{3,} шукатиме послідовність цифр довжиною від 3 і/або більше:

alert( "Мені не 12, а 345678 років".match(/\d{3,}/) ); // "345678"

Давайте повернемось до рядка +38(067)-123-45-67.

Число це послідовність з однієї або більше цифр підряд. Таким чином, регулярний вираз виглядатиме \d{1,}:

let str = "+38(067)-123-45-67";

let numbers = str.match(/\d{1,}/g);

alert(numbers); // 38,067,123,45,67

Скорочення

Існують способи скорочено записати більшу частину часто вживаних квантифікаторів:

+

Означає “один, або більше”, так само як і {1,}.

До прикладу, \d+ шукає числа, які складаються з однієї, або більше цифр:

let str = "+38(067)-123-45-67";

alert( str.match(/\d+/g) ); // 38,067,123,45,67
?

Означає “нуль, або один”, так само як і {0,1}. Інакше кажучи, в такий спосіб ми робимо символ необов’язковим.

До прикладу, шаблон ou?r шукатиме літеру o після якої, можливо, йтиме літера u, і потім літера r.

І таким чином, colou?r знайде обидва слова color та colour:

let str = "Англійською слово колір пишеться як color чи colour?";

alert( str.match(/colou?r/g) ); // color, colour
*

Означає “нуль, або більше”, так само, як і {0,}. Це означає, що символ може бути відсутнім, або повторюватись безліч разів.

До прикладу, \d0* шукає цифру, після якої йде будь-яка кількість нулів (може бути багато, або жодного):

alert( "100 10 1".match(/\d0*/g) ); // 100, 10, 1

Порівняйте з + (один, або більше):

alert( "100 10 1".match(/\d0+/g) ); // 100, 10
// Регулярний вираз не знайшов 1, оскільки 0+ вимагає наявності щонайменше одного нуля

Більше прикладів

Квантифікатори використовуються дуже часто. Вони основні “будівельні блоки” складних регулярних виразів, тож розглянемо ще декілька прикладів.

Регулярний вираз для десяткових дробів (чисел з плаваючою комою): \d+\.\d+

В дії:

alert( "0 1 12.345 7890".match(/\d+\.\d+/g) ); // 12.345

Регулярний вираз для “відкриваючого HTML-тегу без атрибутів”, наприклад, <span>, або <p>.

  1. Найпростіший варіант: /<[a-z]+>/i

    alert( "<body> ... </body>".match(/<[a-z]+>/gi) ); // <body>

    Регулярний вираз шукає символ '<' після якого йдуть одна, або більше літер латиницею, а потім '>'.

  2. Покращений варіант: /<[a-z][a-z0-9]*>/i

    Згідно стандарту, назва HTML-тегу може містити в собі і цифру на будь-якій позиції окрім першої, як наприклад <h1>.

    alert( "<h1>Hi!</h1>".match(/<[a-z][a-z0-9]*>/gi) ); // <h1>

Регулярний вираз “відкриваючого, або закриваючого HTML-тегу без атрибутів”: /<\/?[a-z][a-z0-9]*>/i

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

alert( "<h1>Hi!</h1>".match(/<\/?[a-z][a-z0-9]*>/gi) ); // <h1>, </h1>
Щоб зробити регулярний вираз більш точним, нам часто доводиться його ускладнювати

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

До прикладу, для HTML-тегів без атрибутів ми могли б використати простіший регулярний вираз: <\w+>. Але так як HTML має більш жорсткі вимоги до назв тегів, то шаблон <[a-z][a-z0-9]*> буде більш точним.

Чи можемо ми використовувати <\w+> чи краще писати <[a-z][a-z0-9]*>?

В реальному життя обидва варіанти мають право на існування. Все залежить від того, чи готові ми допустити “зайві” співпадіння з нашим регулярний виразом і наскілльки важко, або легко буде відфільтрувати їх і отримати перелік потрібних нам співпадінь.

Завдання

важливість: 5

Створіть регулярний вираз, який знайде розділовий знак три крапки: 3 (чи навіть більше?) крапок поспіль.

Перевірте:

let regexp = /your regexp/g;
alert( "Привіт!... Як справи?.....".match(regexp) ); // ..., .....

Відповідь:

let regexp = /\.{3,}/g;
alert( "Привіт!... Як справи?.....".match(regexp) ); // ..., .....

Зауважте, що крапка це спецсимвол, тож потребує екранування за допомогою \..

Створіть регулярний вираз, який шукає HTML-кольори записані у форматі #ABCDEF: спершу символ # за яким слідують 6 шістнадцяткових символів.

Приклад використання:

let regexp = /...ваш регулярний вираз.../

let str = "color:#121212; background-color:#AA00ef bad-colors:f#fddee #fd2 #12345678";

alert( str.match(regexp) )  // #121212,#AA00ef

P.S. В цій задачі нам не потрібно враховувати інші формати запису кольорів, як наприклад #123 або rgb(1,2,3) тощо.

Нам потрбіно знайти символ # за яким слідують 6 шістнадцяткових символів.

Шістнадцятковий символ можна описати як [0-9a-fA-F]. Або, якщо застосувати прапорець i , то запис скоротиться до [0-9a-f].

Далі ми позначимо за допомогою квантифікатора, що нам потрібно саме 6 таких шістнадцяткових символів {6}.

І у результаті, отримаємо такий регулярний вираз: /#[a-f0-9]{6}/gi.

let regexp = /#[a-f0-9]{6}/gi;

let str = "color:#121212; background-color:#AA00ef bad-colors:f#fddee #fd2"

alert( str.match(regexp) );  // #121212,#AA00ef

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

alert( "#12345678".match( /#[a-f0-9]{6}/gi ) ) // #123456

Щоб виправити це, ми додамо \b у кінці виразу:

// колір
alert( "#123456".match( /#[a-f0-9]{6}\b/gi ) ); // #123456

// не колір
alert( "#12345678".match( /#[a-f0-9]{6}\b/gi ) ); // null
Навчальна карта

Коментарі

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