Что такое группа без захвата?Что делает (? :)? - PullRequest
1564 голосов
/ 18 августа 2010

Как используется ?: и для чего он нужен?

Ответы [ 15 ]

2079 голосов
/ 18 августа 2010

Позвольте мне попытаться объяснить это на примере.

Рассмотрим следующий текст:

http://stackoverflow.com/
https://stackoverflow.com/questions/tagged/regex

Теперь, если я применю приведенное ниже регулярное выражение к нему ...

(https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?

... Я бы получил следующий результат:

Match "http://stackoverflow.com/"
     Group 1: "http"
     Group 2: "stackoverflow.com"
     Group 3: "/"

Match "https://stackoverflow.com/questions/tagged/regex"
     Group 1: "https"
     Group 2: "stackoverflow.com"
     Group 3: "/questions/tagged/regex"

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

(?:https?|ftp)://([^/\r\n]+)(/[^\r\n]*)?

Теперь мой результат выглядит следующим образом:

Match "http://stackoverflow.com/"
     Group 1: "stackoverflow.com"
     Group 2: "/"

Match "https://stackoverflow.com/questions/tagged/regex"
     Group 1: "stackoverflow.com"
     Group 2: "/questions/tagged/regex"

Видите?Первая группа не была захвачена.Синтаксический анализатор использует его для сопоставления с текстом, но игнорирует его позже, в конечном результате.


РЕДАКТИРОВАТЬ:

По запросу позвольте мне попытаться объяснить группы тоже.

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

Хорошо, представьте, что у вас есть какой-то XML или HTML (учтите, что регулярное выражение может быть не лучшим инструментом для работы , но это приятноВ качестве примера).Вы хотите разобрать теги, чтобы вы могли сделать что-то вроде этого (я добавил пробелы, чтобы было легче понять):

   \<(?<TAG>.+?)\> [^<]*? \</\k<TAG>\>
or
   \<(.+?)\> [^<]*? \</\1\>

У первого регулярного выражения есть именованная группа (TAG), а у второгоодин использует общую группу.Оба регулярных выражения делают одно и то же: они используют значение из первой группы (имя тега), чтобы соответствовать закрывающему тегу.Разница в том, что первый использует имя для соответствия значению, а второй использует групповой индекс (который начинается с 1).

Давайте сейчас попробуем некоторые подстановки.Рассмотрим следующий текст:

Lorem ipsum dolor sit amet consectetuer feugiat fames malesuada pretium egestas.

Теперь давайте воспользуемся этим немым регулярным выражением над ним:

\b(\S)(\S)(\S)(\S*)\b

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

Match "Lorem"
     Group 1: "L"
     Group 2: "o"
     Group 3: "r"
     Group 4: "em"
Match "ipsum"
     Group 1: "i"
     Group 2: "p"
     Group 3: "s"
     Group 4: "um"
...

Match "consectetuer"
     Group 1: "c"
     Group 2: "o"
     Group 3: "n"
     Group 4: "sectetuer"
...

Итак, если мы применяем строку подстановки:

$1_$3$2_$4

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

L_ro_em i_sp_um d_lo_or s_ti_ a_em_t c_no_sectetuer f_ue_giat f_ma_es m_la_esuada p_er_tium e_eg_stas.

Вы также можете использовать именованные группы для подстановок, используя ${name}.

Чтобы поиграть с регулярными выражениями, я рекомендую http://regex101.com/,, который предлагает большое количество деталей о том, как работает регулярное выражение;он также предлагает на выбор несколько двигателей регулярных выражений.

156 голосов
/ 18 августа 2010

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

Скажем, вы хотите сопоставить числовой текст, но некоторые числа могут быть записаны как 1-й, 2-й, 3-й, 4-й, ... Если вы хотитечтобы захватить числовую часть, но не суффикс (необязательно), который вы можете использовать без захвата группы.

([0-9]+)(?:st|nd|rd|th)?

Это будет соответствовать числам в форме 1, 2, 3 ... или в форме1-й, 2-й, 3-й, ... но он будет захватывать только числовую часть.

97 голосов
/ 18 августа 2010

?: используется, когда вы хотите сгруппировать выражение, но не хотите сохранять его как совпадающую / захваченную часть строки.

Примером может служить сопоставление IP-адреса:

/(?:\d{1,3}\.){3}\d{1,3}/

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

32 голосов
/ 18 августа 2010

Это делает группу не захватывающей, что означает, что подстрока, соответствующая этой группе, не будет включена в список захватов.Пример в ruby ​​для иллюстрации разницы:

"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]
19 голосов
/ 04 февраля 2016

ИСТОРИЧЕСКАЯ МОТИВАЦИЯ: Существование не захватывающих групп можно объяснить с помощью скобок.Рассмотрим выражения (a | b) c и a | bc, из-за приоритета конкатенации над |, эти выражения представляют два разных языка ({ac, bc} и {a, bc} соответственно).Тем не менее, скобки также используются в качестве соответствующей группы (как объяснено другими ответами ...).

Если вы хотите иметь круглые скобки, но не захватывать подвыражение, вы используете NON-CAPTURING GROUPВ примере (?: A | b) c

14 голосов
/ 18 августа 2010

Группы, которые захватывают , которые вы можете использовать позже в регулярном выражении для соответствия ИЛИ , вы можете использовать их в заменяющей части регулярного выражения.Создание группы без захвата просто освобождает эту группу от использования по любой из этих причин.

Группы без захвата хороши, если вы пытаетесь захватить много разных вещей, и есть группы, которые вы не хотите захватывать.

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

Пример использования позже в регулярном выражении (обратная ссылка):

<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1> [Находит тег xml(без поддержки ns)]

([A-Z][A-Z0-9]*) - это группа захвата (в данном случае это тэг)

Позже в регулярном выражении будет \1, что означает, что оно будет соответствовать толькотот же текст, который был в первой группе (([A-Z][A-Z0-9]*) группа) (в данном случае он соответствует конечному тегу).

12 голосов
/ 19 января 2017

Позвольте мне попробовать это на примере: -

Код регулярного выражения: - (?:animal)(?:=)(\w+)(,)\1\2

Строка поиска: -

Строка 1 - animal=cat,dog,cat,tiger,dog

Строка 2 - animal=cat,cat,dog,dog,tiger

Строка 3 - animal=dog,dog,cat,cat,tiger

(?:animal) -> Неполная группа 1

(?:=) ->Группа без захвата 2

(\w+) -> Группа захвата 1

(,) -> Группа захвата 2

\1 -> Результат захватагруппа 1, т. е. в строке 1 - кошка, в строке 2 - кошка, в строке 3 - собака.

\2 -> результат захваченной группы 2, т. е. запятая (,)

Итакв этом коде, давая \ 1 и \ 2, мы вспоминаем или повторяем результат захваченной группы 1 и 2 соответственно позже в коде.

В соответствии с порядком кода (?: animal) должна быть группа 1 и(?: =) должна быть группой 2 и продолжаться ..

, но давая?: мы делаем группу совпадений не захваченной (которая не учитывается в сопоставленной группе, поэтому номер группировки начинается ссначала захваченная группа, а не не захваченная), так что повторение результатаиз match-group (?: animal) нельзя вызвать позже в коде.

Надеюсь, это объясняет использование группы без захвата.

введите описание изображения здесь

7 голосов
/ 01 марта 2016

Что ж, я разработчик JavaScript и постараюсь объяснить его значение для JavaScript.

Рассмотрим сценарий, в котором вы хотите сопоставить cat is animal, когда вы хотите сопоставить кошку и животное, и оба должны иметьis между ними.

 // this will ignore "is" as that's is what we want
"cat is animal".match(/(cat)(?: is )(animal)/) ;
result ["cat is animal", "cat", "animal"]

 // using lookahead pattern it will match only "cat" we can
 // use lookahead but the problem is we can not give anything
 // at the back of lookahead pattern
"cat is animal".match(/cat(?= is animal)/) ;
result ["cat"]

 //so I gave another grouping parenthesis for animal
 // in lookahead pattern to match animal as well
"cat is animal".match(/(cat)(?= is (animal))/) ;
result ["cat", "cat", "animal"]

 // we got extra cat in above example so removing another grouping
"cat is animal".match(/cat(?= is (animal))/) ;
result ["cat", "animal"]
7 голосов
/ 08 марта 2014

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

6 голосов
/ 11 мая 2018

tl; dr группы без захвата, как следует из названия, являются частями регулярного выражения, которые вы не хотите включать в совпадение, а ?: - это способ определить группу как не захватывая.

Допустим, у вас есть адрес электронной почты example@example.com. Следующее регулярное выражение создаст две группы , часть id и часть @ example.com. (\p{Alpha}*[a-z])(@example.com). Для простоты мы извлекаем все доменное имя, включая символ @.

Теперь, скажем, вам нужна только часть идентификатора адреса. То, что вы хотите сделать, это получить первую группу результата совпадения, заключенную в регулярное выражение в (), и способ сделать это - использовать синтаксис группы без захвата, то есть ?:. Таким образом, регулярное выражение (\p{Alpha}*[a-z])(?:@example.com) вернет только часть идентификатора электронного письма.

...