Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
133 lines (84 sloc) 7.22 KB

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

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

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

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

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

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

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

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

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

```js run
alert( "Мне 12345 лет".match(/\d{5}/) ); //  "12345"
```

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Пример ниже находит цифру вместе со всеми нулями, которые идут за ней (но могут и не идти):

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

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

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

Ещё примеры

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

Регэксп "десятичная дробь" (число с точкой внутри): pattern:\d+\.\d+ : В действии: js run alert( "0 1 12.345 7890".match(/\d+\.\d+/g) ); // 12.345

Регэксп "открывающий HTML-тег без атрибутов", такой как <span> или <p>: pattern:/<[a-z]+>/i : Пример:

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

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

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

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

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

```js run
alert( "<h1>Привет!</h1>".match(/<\/?[a-z][a-z0-9]*>/gi) ); // <h1>, </h1>
```
В этих примерах мы видим общее правило, которое повторяется из раза в раз: чем точнее регулярное выражение, тем оно длиннее и сложнее.

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

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

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

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