en.javascript.info/10-regular-expressions-javascript/9-regexp-groups/article.md
2015-02-27 13:21:58 +03:00

6.2 KiB
Raw Blame History

Группы

Часть шаблона может быть заключена в скобки (...). Такие выделенные части шаблона называют "скобочными выражениями" или "скобочными группами".

У такого выделения есть два эффекта:

  1. Он позволяет выделить часть совпадения в отдельный элемент массива при поиске через [:String#match] или [:RegExp#exec].
  2. Если поставить квантификатор после скобки, то он применится *ко всей скобке*, а не всего лишь к одному символу.

[cut] В примере ниже, шаблон (go)+ находит один или более повторяющихся 'go':

//+ run
alert( 'Gogogo now!'.match( /(go)+/i );  // "Gogogo"

Без скобок, шаблон /go+/ означал бы g, после которого идёт одна или более o, например: goooo.

Скобки нумеруются слева направо. Поисковой движок запоминает содержимое каждой скобки и позволяет обращаться к нему, в том числе -- в шаблоне и строке замены.

Например, найти HTML-тег можно шаблоном <.*?>. Скорее всего, после поиска мы захотим что-то сделать с результатом, и нас будет интересовать содержимое <...>.

Для удобства заключим его в скобки: <(.*?)>. Тогда содержимое скобок можно будет получить отдельно.

Используем метод [:String#match]. В результирующем массиве будет сначала всё совпадение, а далее -- скобочные группы, в данном случае -- только одна:

//+ run
var str = '<h1>Привет, мир!</h1>'
var reg = /<(.*?)>/ 

alert( str.match(reg) ) // массив: <h1>, h1

Для поиска всех совпадений, как мы обсуждали ранее, используется метод [:RegExp#exec].

Скобки могут быть и вложенными. В этом случае нумерация также идёт слева направо.

Например, в строке <span class="my"> нас может интересовать отдельно тег span и, для примера, его первая буква.

Добавим скобки в регулярное выражение:

//+ run
var str = '<span class="my">';

reg = /<(([a-z])[a-z0-9]*).*?>/;

alert( str.match(reg) );  // <span class="my">, span, s

Вот так выглядят скобочные группы:

На нулевом месте -- всегда совпадение полностью, далее -- группы. Их вложенность означает всего лишь, что группа 1 содержит группу 2. Нумерация всегда идёт слева направо, по открывающей скобке.

Даже если скобочная группа необязательна и не входит в совпадение, соответствующий элемент массива существует (и равен undefined).

Например, рассмотрим регэксп a(z)?(c)?. Он ищет "a", за которой не обязательно идёт буква "z", за которой необязательно идёт буква "c".

Если напустить его на строку из одной буквы "a", то результат будет таков:

//+ run
match = 'a'.match( /a(z)?(c)?/ )  

alert(match.length); // 3
alert(match[0]); // a
alert(match[1]); // undefined
alert(match[2]); // undefined

Массив получился длины 3, но все скобочные группы -- undefined.

А теперь более сложная ситуация, строка ack:

//+ run
match = 'ack'.match( /a(z)?(c)?/ )  

alert(match.length); // 3
alert(match[0]); // ac, всё совпадение
alert(match[1]); // undefined, для (z)? ничего нет
alert(match[2]); // c

Длина массива результатов по-прежнему 3. Она постоянна. А вот для скобочной группы (z)? в ней ничего нет.

Скобочную группу можно исключить из запоминаемых и нумеруемых, добавив в её начало ?:

Бывает так, что скобки нужны, чтобы квантификатор правильно применился, а вот запоминать её в массиве не нужно. Тогда мы просто ставим сразу после открывающей скобки ?:

В примере ниже есть скобочная группа (go-?), которая сама по себе не интересна, но входит в результаты:

//+ run
var str = "Go-go John!";
*!*
var reg = /(go-?)* (\w+)/i;
*/!*

var result = str.match(reg);

alert( result[0] ); // Go-go John
alert( result[1] ); // go
alert( result[2] ); // John

Исключим её из запоминаемых:

//+ run
var str = "Go-go John!";
*!*
var reg = /(?:go-?)* (\w+)/i;
*/!*

var result = str.match(reg);

alert( result[0] ); // Go-go John
alert( result[1] ); // John