2012-04-25 3 views
1

Я пытаюсь соответствовать строки следующего формата:Не удается захватить группы в строке с помощью Regex

S->A 
S->AbCd 
S->A|b|C|d 
S->Ab|B|cde|dB 

То есть, на крайней левой стороне есть ровно один капитал латинского алфавита символ следуют ' -> 'литерал. После этого буквально следует ровно один символ столичного/неклассического латинского алфавита или конкатенация таких символов, за которыми также могут следовать такие группы символов, ограниченные символом '|' символ.
Также я хочу, чтобы не только проверить, придерживается ли вся строка в этом формате, но также сможет захватить как левый символ капитала, так и все группы символов после литерала «->». До сих пор я пришел с этим регулярным выражением:

([A-Z]{1})->([a-zA-Z]+)(?:(?:\|)([a-zA-Z]+))* 

Если я проверить его против, например, эта строка:

S->Ab|B|c|d 

Я получаю следующие результаты (тестирование сделано с RegexBuddy):

Match 1: S->Ab|B|c|d 
Group 1: S 
Group 2: Ab 
Group 3: d 

Хорошо, что мое регулярное выражение соответствует всей строке (что является правильным). Однако проблема очевидна: мое регулярное выражение захватывает только первую и последнюю группу символов после литерала «->». Зачем? Основываясь на моем понимании регулярных выражений этой части выражения

(?:(?:\|)([a-zA-Z]+))* 

должны соответствовать ВСЕХ разграниченных группам символов. Я считаю, что это связано с тем, что описано в статье 'Repeating a Capturing Group vs. Capturing a Repeated Group'. Я пытался немного поиграть с моим регулярным выражением, но все же не получил удовлетворительных результатов. Какие-либо предложения?

+3

На каком языке находится регулярное выражение? –

+0

Если левая часть должна быть латинской буквой, вы должны удалить [a-z] - часть. –

ответ

1

Да, ваша проблема в том, что вы повторяете группу захвата.

(?:(?:\|)([a-zA-Z]+))* 
     ^^^^^^^^^^^ 
      third group 

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

Вы можете захватить вашу повторено группа, как это

([a-zA-Z]{1})->([a-zA-Z]+)((?:(?:\|)[a-zA-Z]+)*) 

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

Match 1: S->Ab|B|c|d 
Group 1: S 
Group 2: Ab 
Group 3: |B|c|d 
+0

Спасибо за советы. Однако правильно ли я понимаю, что нет никакого способа писать регулярное выражение, которое создавало бы отдельную группу для всех совпадающих элементов с префиксом '|'? – davidgale

+0

На каком языке вы используете? Большинство нет, но я думаю, что .net способен это сделать (и я слышал, как Perl 6). – stema

1

Синтаксис (?:...) означает a не захватывающий группа.

Если вы хотите взять группу, вы должны использовать вместо этого (...).

Попробуйте это:

([a-zA-Z]{1})->([a-zA-Z]+)(\|[a-zA-Z]+)* 

Если вы хотите, чтобы каждый элемент по отдельности можно разделить на ограничителе.

2

В регулярном выражении имеется только три пары скобок для записи, поэтому вы можете получить только три группы (и это связано с «повторением группы по сравнению с повторением группы захвата»). Количество групп всегда фиксировано.

Использование Perl-подобный интервал m//x разделить вещи для ясности:

([a-zA-Z]{1}) -> ([a-zA-Z]+) (?: (?:\|) ([a-zA-Z]+))* 
^-----------^  ^---------^    ^---------^ 

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

([a-zA-Z]{1}) -> ([a-zA-Z]+) ((?:\|) (?:[a-zA-Z]+))* 

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

1

группа захват 3 матча всех символы ([a-zA-Z]+) - это будет первый матч «B», то он заменяется на «c», поскольку регулярное выражение прогрессирует после следующего | и, наконец, оно заменяется на «d», как в вашем результате.

Смежные вопросы