Вопрос: Что такое группа, не связанная с захватом? Что делает (? :)?


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


1289


источник


Ответы:


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

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

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

Теперь, если я применил regex ниже над ним ...

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

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

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

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

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

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

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

Match "https://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 (имейте в виду, что regex не может быть лучшим инструментом для работы , но это хорошо, как пример). Вы хотите проанализировать теги, чтобы вы могли сделать что-то вроде этого (я добавил места, чтобы было легче понять):

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


1794



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

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

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

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


131



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

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

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

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


86



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

"abc".match(/(.)(.)./).captures #=> ["a","b"]
"abc".match(/(?:.)(.)./).captures #=> ["b"]

26



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

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

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

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

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

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

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


12



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

Если вы хотите иметь скобки, но не захватывать подвыражение, вы используете НЕПРАВИЛЬНЫЕ ГРУППЫ. В этом примере (?: A | b) c


12



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

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

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

Линия 1 - животное = кошка, собака, кошка, тигр, собака

Строка 2 - животное = кошка, кошка, собака, собака, тигр

Строка 3 - животное = собака, собака, кот, кот, тигр

(?:animal)-> Не захваченная группа 1

(?:=)-> Не взятая группа 2

(\w+)-> Захваченная группа 1

(,)-> Захваченная группа 2

\1-> результат захваченной группы 1 i.e В строке 1 находится cat, In Line 2 - cat, In Line 3 - собака.

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

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

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

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

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

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


7



Well I am a JavaScript developer and will try to explain its significance pertaining to JavaScript.

Consider a scenario where you want to match cat is animal when you would like match cat and animal and both should have a is in between them.

 // 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"]

6