2013-12-22 3 views
0

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

Пример: Регулярное выражение должно соответствовать следующие строки (это упрощенно, А и В могут быть сложными):

XAB 
XBA 
XA 
XB 
X 

Это не может соответствовать XAA, Xbb, XABA, XABB, XBAA

Вот то, что я до сих пор:

/(X)(?:(A)|(B)){0,2}$/

Это позволяет для повторения (например, как XAA), и, кажется, вызывает проблемы с ХВ в PHP с пустой элемент массива.

EDIT: Забыл упомянуть, что мне нужно получить фактические значения X, A и B (если доступно). Это не просто совпадение полной строки.

+0

Вы в основном говорят, что это может 't сопоставлять 'A' или' B' более одного раза, так почему бы вам просто не сделать чек для этого и не покончить с регулярным выражением? 'if (substr_count ($ string, 'A')> = 2) echo 'error!';' –

+0

Вот демо-версия regex, если вы хотите придерживаться ее ... http://regex101.com/r/kD2fA1 –

ответ

1

Использование negative lookahead assertions:

/(X)(?!A{2})(?!B{2})(?:(A)|(B)){0,2}$/ 

Объяснение:

(X)  # Match and capture X 
(?!A{2}) # Assert that it's impossible to match AA 
(?!B{2}) # Same for BB 
(?:  # Non-capturing group: 
(A)  # Match and capture A 
|   # or 
(B)  # Match and capture B 
){0,2} # Do this 0-2 times 
$   # Then match the end of the string 
1

Чистейший способ был бы определить каждую группу, а затем использовать эти определения в определенном порядке:

# Start defining 
(?(DEFINE) 
    (?<X>xrules) 
    (?<A>arules) 
    (?<B>brules) 
) 
# End defining 
^     # begin of string 
(?&X)    # Use rule X 
    (?:    # non-capturing group 
     (?&A)(?&B)? # Use rule A and make rule B optional 
    |     # or 
     (?&B)(?&A)? # Use rule B and make rule A optional 
    )?    # make it optional 
$     # end of string 

Конечно, вы можете изменить xrules с действительным регулярным выражением, как [a-z]+ и brules с [A-Z]+.

Online demo

+0

Почему это решение не соответствует X, A или B отдельно, как это делает Тим? –

+0

@ user371699 Потому что это не так. Ну, вы всегда можете обернуть некоторые группы захвата, но это станет уродливым. Возможно, вы могли бы объединить два ответа. – HamZa

+0

Я думал, что что-либо в скобках будет захвачено, если оно не имеет '?:'. Почему это кажется исключением? –

0

Ваш вопрос может иметь этот заголовок: "Как не повторить необязательная группа?".

$pattern = <<<'LOD' 
~ 
    (?(DEFINE) 
     (?<X> FOO) 
     (?<A> BAR) 
     (?<B> BAZ) 
    ) 

^ \g<X> (?: \g<A> (?! .* \g<A>) | \g<B> (?! .* \g<B>)){0,2} $ 
~xs 
LOD; 

\g<A> (?! .* \g<A>) вынуждает группу А присутствовать только один раз в строке, из-за отрицательного предпросмотра (то есть: «не следует ничего и группы А»)