Что такое группа без захвата в регулярных выражениях?

Для любопытства другой способ выполнить это (что дает тот же результат, что и ответ Джона Скита):

firstList.Join(secondList, x => true, y => true, (m, n) => new { m, n });
1570
задан Emma 28 July 2019 в 00:45
поделиться

5 ответов

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

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

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/ , который предлагает много подробностей о том, как работает регулярное выражение; он также предлагает на выбор несколько движков регулярных выражений.

2182
ответ дан 22 November 2019 в 20:13
поделиться

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

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

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

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

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

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

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

14
ответ дан 22 November 2019 в 20:13
поделиться

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

"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]
35
ответ дан 22 November 2019 в 20:13
поделиться

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

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

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

Это будет соответствовать числам в форме 1, 2, 3 ... или в форме 1-го, 2-го, 3-го, ... но будет фиксироваться только числовая часть.

164
ответ дан 22 November 2019 в 20:13
поделиться

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

Примером может быть что-то для соответствия IP-адресу:

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

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

100
ответ дан 22 November 2019 в 20:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: