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

Рассмотрим ту же задачу, что и ранее – взять телефон вида +7(903)-123-45-67 и найти все числа в нём. Но теперь нас интересуют не цифры по отдельности, а именно числа, то есть результат вида 7, 903, 123, 45, 67.

Для поиска цифр по отдельности нам было достаточно класса \d. Но здесь нужно искать числа – последовательности из 1 или более цифр.

Количество {n}

Количество повторений символа можно указать с помощью числа в фигурных скобках: {n}.

Такое указание называют квантификатором (от англ. quantifier).

У него есть несколько подформ записи:

Точное количество: {5}

Регэксп \d{5} обозначает ровно 5 цифр, в точности как \d\d\d\d\d.

Следующий пример находит пятизначное число.

alert( "Мне 12345 лет".match(/\d{5}/) ); //  "12345"
Количество от-до: {3,5}

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

alert( "Мне не 12, а 1234 года".match(/\d{3,5}/) ); // "1234"

Последнее значение можно и не указывать. Тогда выражение \d{3,} найдет числа, длиной от трех цифр:

alert( "Мне не 12, а 345678 лет".match(/\d{3,}/) ); // "345678"

В случае с телефоном нам нужны числа – одна или более цифр подряд. Этой задаче соответствует регулярное выражение \d{1,}:

var str = "+7(903)-123-45-67";

alert( str.match(/\d{1,}/g) ); // 7,903,123,45,67

Короткие обозначения

Для самых часто востребованных квантификаторов есть специальные короткие обозначения.

+

Означает «один или более», то же что {1,}.

Например, \d+ находит числа – последовательности из 1 или более цифр:

var str = "+7(903)-123-45-67";

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

Означает «ноль или один», то же что и {0,1}. По сути, делает символ необязательным.

Например, регэксп ou?r найдёт o, после которого, возможно, следует u, а затем r.

Этот регэксп найдёт or в слове color и our в colour:

var str = "Можно писать color или colour (британский вариант)";

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

Означает «ноль или более», то же что {0,}. То есть, символ может повторяться много раз или вообще отсутствовать.

Пример ниже находит цифру, после которой идёт один или более нулей:

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

Сравните это с '+' (один или более):

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

Ещё примеры

Эти квантификаторы принадлежат к числу самых важных «строительных блоков» для сложных регулярных выражений, поэтому мы рассмотрим ещё примеры.

Регэксп «десятичная дробь» (число с точкой внутри): \d+\.\d+

В действии:

alert( "0 1 12.345 7890".match(/\d+\.\d+/g) ); // 12.345
Регэксп «открывающий HTML-тег без атрибутов», такой как <span> или <p>: /<[a-z]+>/i

Пример:

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

Это регулярное выражение ищет символ '<', за которым идут одна или более букв английского алфавита, и затем '>'.

Регэксп «открывающий HTML-тег без атрибутов» (лучше): /<[a-z][a-z0-9]*>/i

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

alert( "<h1>Привет!</h1>".match(/<[a-z][a-z0-9]*>/gi) ); // <h1>
Регэксп «открывающий или закрывающий HTML-тег без атрибутов»: /<\/?[a-z][a-z0-9]*>/i

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

alert( "<h1>Привет!</h1>".match(/<\/?[a-z][a-z0-9]*>/gi) ); // <h1>, </h1>
Точнее – значит сложнее

В этих примерах мы видим общее правило, которое повторяется из раза в раз: чем точнее регулярное выражение, тем оно длиннее и сложнее.

Например, для HTML-тегов, скорее всего, подошло бы и более короткое регулярное выражение <\w+>.

Так как класс \w означает "любая цифра или английская буква или '_', то под такой регэксп подойдут и не теги, например <_>. Однако он гораздо проще, чем более точный регэксп <[a-z][a-z0-9]*>.

Подойдёт ли нам <\w+> или нужно использовать именно <[a-z][a-z0-9]*>?

В реальной жизни допустимы оба варианта. Ответ на подобные вопросы зависит от того, насколько реально важна точность и насколько сложно потом будет отфильтровать лишние совпадения (если появятся).

Задачи

важность: 5

Напишите регулярное выражения для поиска многоточий: трёх или более точек подряд.

Проверьте его:

var reg = /ваше выражение/g;
alert( "Привет!... Как дела?.....".match(reg) ); // ..., .....

Решение:

var reg = /\.{3,}/g;
alert( "Привет!... Как дела?.....".match(reg) ); // ..., .....

Заметим, что символ . является специальным, значит его надо экранировать, то есть вставлять как \..

Напишите регулярное выражение для поиска HTML-цвета, заданного как #ABCDEF, то есть # и содержит затем 6 шестнадцатеричных символов.

Пример использования:

var re = /*...ваше регулярное выражение...*/

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

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

Итак, нужно написать выражение для описания цвета, который начинается с «#», за которым следуют 6 шестнадцатеричных символов.

Шестнадцатеричный символ можно описать с помощью [0-9a-fA-F]. Мы можем сократить выражение, используя не чувствительный к регистру шаблон [0-9a-f].

Для его шестикратного повторения мы будем использовать квантификатор {6}.

В итоге, получаем выражение вида /#[a-f0-9]{6}/gi.

var re = /#[a-f0-9]{6}/gi;

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

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

Проблема этого выражения в том, что оно находит цвет и в более длинных последовательностях:

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

Чтобы такого не было, можно добавить в конец \b:

// цвет
alert( "#123456".match( /#[a-f0-9]{6}\b/gi ) ); // #123456

// не цвет
alert( "#12345678".match( /#[a-f0-9]{6}\b/gi ) ); // null

Создайте регэксп, который ищет все положительные числа, в том числе и с десятичной точкой.

Пример использования:

var re = /* ваш регэксп */

var str = "1.5 0 12. 123.4.";

alert( str.match(re) );   // 1.5, 0, 12, 123.4

Целое число – это \d+.

Десятичная точка с дробной частью – \.\d+.

Она не обязательна, так что обернём её в скобки с квантификатором '?'.

Итого, получилось регулярное выражение \d+(\.\d+)?:

var re = /\d+(\.\d+)?/g

var str = "1.5 0 12. 123.4.";

alert( str.match(re) );   // 1.5, 0, 12, 123.4

Создайте регэксп, который ищет все числа, в том числе и с десятичной точкой, в том числе и отрицательные.

Пример использования:

var re = /* ваш регэксп */

var str = "-1.5 0 2 -123.4.";

alert( str.match(re) );   // -1.5, 0, 2, -123.4

Целое число с необязательной дробной частью – это \d+(\.\d+)?.

К этому нужно добавить необязательный - в начале:

var re = /-?\d+(\.\d+)?/g

var str = "-1.5 0 2 -123.4.";

alert( str.match(re) );   // -1.5, 0, 2, -123.4
Карта учебника

Комментарии

перед тем как писать…
  • Приветствуются комментарии, содержащие дополнения и вопросы по статье, и ответы на них.
  • Для одной строки кода используйте тег <code>, для нескольких строк кода — тег <pre>, если больше 10 строк — ссылку на песочницу (plnkr, JSBin, codepen…)
  • Если что-то непонятно в статье — пишите, что именно и с какого места.