2014-10-01 4 views
1

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

<b>(ABC)</b> 
<b> (ABC) </b> 
<b> abc (ABC) fgt </b> 

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

"(<b>.*?\()([A-Z]+)(\).*?</b>)" 

Это прекрасно работает для примеров выше, но если предложение является следующее:

<b></b>(ABCA)<b>(ABCB)</b> 

Затем я ошибаюсь. Regex находит первое появление <b> и показывается до первого (. Затем он пропускает все слова до </b>. Это неверно. Правильное совпадение должно быть <b>(ABCB)</b>. Как это исправить?

+1

, что было бы ожидать выход для указанной выше строки? –

ответ

1

Если вы хотите, чтобы регулярное выражение не пересекало границы тегов, маркер «match anything» .* слишком свободен, потому что «все» также охватывает теги.

Вы можете использовать negative lookahead assertion, чтобы убедиться, что <b> и </b> не может быть частью матча:

(<b>(?:(?!</?b>).)*\()([A-Z]+)(\)(?:(?!</?b>).)*</b>) 

Попробуй live on regex101.com.

Объяснение:

(  # Match into group 1: 
<b>  # <b> 
(?:  # Start of non-capturing group 
    (?!  # Match only if it's impossible to match 
    </?b> # <b> or </b> 
)  # (End of lookahead assertion) 
    .  # Match any character 
)*  # Repeat as many times as possible 
\(  # Then match a (
)   # End of group 1 
([A-Z]+) # Match one or more uppercase ASCII letters --> group 2 
(  # Match into group 3: 
\)  # Match) 
(?:(?!</?b>).)* # as before, match anything except <b> or </b> 
</b>  # Match </b> 
)   # End of group 3 
1

Заменить .*? с [^<>]* в своем регулярном выражении, так что он будет соответствовать любому символу, но не < или > ноля или более раз. Это гарантирует отсутствие метки, находящейся между открытием и закрытием тегов <b>.

(<b>[^<>]*?\()([A-Z]+)(\)[^<>]*?</b>) 

DEMO

+1

+1, хотя, конечно, это предотвращает появление каких-либо * тегов от '' и '', что должно быть достаточно, если не произойдет что-то вроде' (ABCD). Думаю, вам не нужно хранить ленивые кванторы. –

+0

Да, если вход содержит ' (ABCD)', то мой не будет работать. –