en.javascript.info/11-regular-expressions-javascript/7-regexp-quantifiers/article.md
2015-03-24 00:03:51 +03:00

7.8 KiB
Raw Blame History

Квантификаторы +, *, ? и {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.

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

//+ run
alert( "Мне 12345 лет".match(/\d{5}/) ); //  "12345"
Количество от-до: `{3,5}`
Для того, чтобы найти, например, числа размером от трёх до пяти знаков, нужно указать границы в фигурных скобках: \d{3,5}
//+ run
alert( "Мне не 12, а 1234 года".match(/\d{3,5}/) ); // "1234"

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

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

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

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

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

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

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

`+`
Означает "один или более", то же что `{1,}`.

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

//+ run
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:

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

alert( str.match(/colou?r/g) ); // color, colour
`*`
Означает "ноль или более", то же что `{0,}`. То есть, символ может повторяться много раз или вообще отсутствовать.

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

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

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

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

Ещё примеры

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

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

В действии:

//+ run
alert( "0 1 12.345 7890".match(/\d+\.\d+/g) ); // 123.45
Регэксп "открывающий HTML-тег без атрибутов", такой как `` или `

`: /<[a-z]+>/i

Пример:
//+ run
alert( "<BODY> ... </BODY>".match(/<[a-z]+>/gi) ); // <BODY>

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

Регэксп "открывающий HTML-тег без атрибутов" (лучше): /<[a-z][a-z0-9]*>/i
Здесь регулярное выражение расширено: в соответствие со стандартом, HTML-тег может иметь символ на любой позиции, кроме первой, например `

`.
//+ run
alert( "<h1>Привет!</h1>".match(/<[a-z][a-z0-9]*>/gi) ); // <h1>

Регэксп "открывающий или закрывающий HTML-тег без атрибутов": /<\/?[a-z][a-z0-9]*>/i
В предыдущий паттерн добавили необязательный слэш /? перед тегом. Его понадобилось заэкранировать, чтобы JavaScript не принял его за конец шаблона.
//+ run
alert( "<h1>Привет!</h1>".match(/<\/?[a-z][a-z0-9]*>/gi) ); // <h1>, </h1>

[smart header="Точнее -- значит сложнее"] В этих примерах мы видим общее правило, которое повторяется из раза в раз: чем точнее регулярное выражение, тем оно длиннее и сложнее.

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

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

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

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