6.2 KiB
Группы
Часть шаблона может быть заключена в скобки (...)
. Такие выделенные части шаблона называют "скобочными выражениями" или "скобочными группами".
У такого выделения есть два эффекта:
- Он позволяет выделить часть совпадения в отдельный элемент массива при поиске через [:String#match] или [:RegExp#exec].
- Если поставить квантификатор после скобки, то он применится *ко всей скобке*, а не всего лишь к одному символу.
[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