Объединить несколько регулярных выражений в один RE

Я написал 2 RE, чтобы соответствовать нескольким строковым последовательностям в String. например. допустим, что два регулярных выражения: RE1, RE2. Строки могут быть в этих четырех формах:

1) Match ONLY RE1 'one or more times'
2) Match ONLY RE2 'one or more times'
3) Match RE1 'one or more times' AND match RE2 'one or more times'
4) Match NEITHER RE1 NOR RE2 

В настоящее время я использую if для проверки каждого из них, но я знаю его очень дорого, поскольку я выполняю сопоставление для конкретной строки несколько раз. Я думал об использовании 'или' |, но проблема с этим - это регулярное выражение, которое перестанет совпадать, если оно найдет первую совпадающую последовательность и не будет продолжать находить других. Я хочу найти соответствующие последовательности "один или несколько раз".

Update:

eg: RE1 = (\d{1,3}[a-zA-Z]?/\d{1,3}[a-zA-Z]?)
    RE2 = (\babc\b)
String: *some string* 100/64h *some string* 120h/90 *some string* abc 200/100 abc *some string* 100h/100f

Matches: '100/64h', '120h/90', 'abc', '200/100', 'abc', '100h/100f'

Как я могу объединить эти 2 RE, чтобы сделать мою программу эффективной. Я использую python для кодирования этого.

Ответ 1

Вы говорите: "Я знаю, что это очень дорого, поскольку я выполняю сопоставление для определенной строки несколько раз". Это говорит мне о том, что вы выполняете каждый RE несколько раз. В этом случае вы делаете ошибку, которая может быть решена без написания более сложного RE.

re1_matches = re.findall(re1, text)
re2_matches = re.findall(re2, text)

Это приведет к двум спискам совпадений. Затем вы можете выполнять логические операции над этими списками для генерации любых результатов, которые вам нужны; или вы можете связать их, если вам нужны все совпадения в одном списке. Вы также можете использовать re.match (матч привязан в начале строки) или re.search (в любом месте в строке) для каждого из них, если вам не нужны списки результатов, но нужно только знать, что есть совпадение.

В любом случае создание более сложного RE в этом случае, вероятно, необязательно или желательно.

Но мне не сразу понятно, что именно вы хотите, поэтому я мог ошибаться.


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

>>> re1 = r'(\d{1,3}[a-zA-Z]?/\d{1,3}[a-zA-Z]?)'
>>> re2 = r'(\babc\b)'
>>> re.findall(re1, text)
['100/64h', '120h/90', '200/100', '100h/100f']
>>> re.findall(re2, text)
['abc', 'abc']
>>> re1_matches = re.findall(re1, text)
>>> re2_matches = re.findall(re2, text)
>>> rex_nomatch = re.findall('conglomeration_of_sandwiches', text)

and возвращает первый результат False или конечный результат, если все результаты True.

>>> not re1_matches and re2_matches
False

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

>>> not rex_nomatch and re1_matches
['100/64h', '120h/90', '200/100', '100h/100f']

Аналогично:

>>> not rex_nomatch and re2_matches
['abc', 'abc']

Если вы просто хотите знать, что оба RE сгенерировали совпадения, но больше не нужны, вы можете сделать это:

>>> re1_matches and re2_matches
['abc', 'abc']

Наконец, здесь компактный способ получить конкатенацию, если оба RE генерируют совпадения:

>>> re1_matches and re2_matches and re1_matches + re2_matches
['100/64h', '120h/90', '200/100', '100h/100f', 'abc', 'abc']

Ответ 2

Вам нужно избежать\во втором RE:

RE1 = '(\d{1,3}[a-zA-Z]?/\d{1,3}[a-zA-Z]?)'
RE2 = '(\\babc\\b)'
s = '*some string* 100/64h *some string* 120h/90 *some string* abc 200/100 abc *some string* 100h/100f'


p = re.compile('('+RE2+'|'+RE1+')');
matches = p.findall(s)

for match in matches:
    print(match[0])

Ответ 3

Я думал об использовании 'или' |, но проблема с этим - это регулярное выражение, которое перестанет соответствовать, если оно найдет первую совпадающую последовательность и не будет продолжать искать других.

Для чего re.findall.

>>> import re
>>> RE = r'(?:\d{1,3}[a-zA-Z]?/\d{1,3}[a-zA-Z]?)|(?:\babc\b)'
>>> string = '*some string* 100/64h *some string* 120h/90 *some string* abc 200/100 abc *some string* 100h/100f'
>>> re.findall(RE, string)
['100/64h', '120h/90', 'abc', '200/100', 'abc', '100h/100f']

Обратите внимание на использование не захватывающих круглых скобок (материал (?:...)). Если регулярное выражение использовало скобки для группировки записей как обычные, re.findall возвращал [('100/64h', ''), ('120h/90', ''), ('', 'abc'), ('200/100', ''), ('', 'abc'), ('100h/100f', '')].

Ответ 4

Использование | в вашем регулярном выражении и re.findall(), вероятно, путь, вот пример:

>>> pattern = re.compile(r"(\d{1,3}[a-zA-Z]?/\d{1,3}[a-zA-Z]?|\babc\b)")
>>> pattern.findall("*some string* 100/64h *some string* 120h/90 *some string* abc 200/100 abc *some string* 100h/100f")
['100/64h', '120h/90', 'abc', '200/100', 'abc', '100h/100f']

Если для ваших шаблонов допустимо совпадение, это не сработает.

Ответ 5

Если RE1 и RE2 могут совпадать с одинаковыми символами строки, проверьте их отдельно (RE1 соответствует строке, RE2 соответствует строке).