Python: определение объединения регулярных выражений - PullRequest
5 голосов
/ 18 июля 2010

У меня есть список шаблонов, таких как

list_patterns = [': error:', ': warning:', 'cc1plus:', 'undefine reference to']

что я хочу сделать, это создать объединение всех из них, получая регулярное выражение, которое соответствует каждому элементу в list_patterns [но, по-видимому, не совпадает ни с одним re в list_patterns - msw]

re.compile(list_patterns)

Возможно ли это?

Ответы [ 6 ]

10 голосов
/ 18 июля 2010

Есть несколько способов сделать это.Самое простое:

list_patterns = [': error:', ': warning:', 'cc1plus:', 'undefine reference to']
string = 'there is an : error: and a cc1plus: in this string'
print re.findall('|'.join(list_patterns), string)

Вывод:

[': error:', 'cc1plus:']

, что хорошо, если конкатенация ваших шаблонов поиска не нарушает регулярное выражение (например, если один из них содержит специальное регулярное выражение)символ как открывающая скобка).Вы можете справиться с этим следующим образом:

list_patterns = [': error:', ': warning:', 'cc1plus:', 'undefine reference to']
string = 'there is an : error: and a cc1plus: in this string'
pattern = "|".join(re.escape(p) for p in list_patterns)
print re.findall(pattern, string)

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

Теперь какой из них вы используете, зависит от вашего списка шаблонов.Являются ли они регулярными выражениями и, таким образом, могут считаться действительными?Если это так, первое, вероятно, будет уместным.Если они являются строками, используйте второй метод.

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

2 голосов
/ 18 июля 2010
list_regexs = [re.compile(x) for x in list_patterns]
1 голос
/ 18 июля 2010

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

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

  • Удаление любых дубликатов в list_patterns.(Может быть лучше начать с набора, затем превратить его в список с обратным сортированием без дубликатов).
  • re.escape () элементы списка.
  • Окружите каждый элемент в отдельности группой (... ).
  • '|' .join () всех групп.
  • Найдите набор индексов всех сопоставляемых групп и сравните его длину с len(list_patterns).

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

Код будет выглядеть примерно так:

import re

def usedgroupindex(indexabledata):
    for i,datum in enumerate(indexabledata):
        if datum: return i
    # return None

def findallstrings(list_patterns, string):
    lp = sorted(set(list_patterns), reverse=True)
    pattern = "|".join("(%s)" % re.escape(p) for p in lp)
    # for m in re.findall(pattern, string): print (m, usedgroupindex(m))
    return ( len(set(usedgroupindex(m) for m in re.findall(pattern, string)))
             == len(lp) )

list_patterns = [': error:', ': warning:', 'cc1plus:', 'undefine reference to']
string = ' XZX '.join(list_patterns)

print ( findallstrings(list_patterns, string) )
1 голос
/ 18 июля 2010

Как насчет

ptrn = re.compile('|'.join(re.escape(e) for e in list_patterns))

Обратите внимание на использование re.escape(), чтобы избежать непредвиденных последствий из-за присутствия таких символов, как () [] |. + * И т. Д. В некоторых строках.Предполагая, что вы этого хотите, в противном случае пропустите escape().

. Это также зависит от того, как вы намереваетесь «потреблять» это выражение - только для поиска соответствия или вы хотите собрать соответствующие группы обратно?

1 голос
/ 18 июля 2010

Вы хотите шаблон, который соответствует любому элементу в списке? Не будет ли это просто:

': error:|: warning:|cc1plus:|undefine reference to'?

Или в коде Python:

re.compile("|".join(list_patterns))
0 голосов
/ 18 июля 2010

регулярное выражение, соответствующее каждому элементу в списке

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

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

Для сопоставления по порядку, '.*?'.join(list_patterns) должен хорошо служить вам (если элементы действительно должны восприниматься как шаблоны RE - если они должны восприниматься как буквальные)вместо строк '.*?'.join(re.escape(p) for p list_patterns)).

Для сопоставления любого порядка сами по себе регулярные выражения не предоставляют прямой поддержки.Вы можете взять все перестановки списка (например, с itertools.permutations), объединить каждую из них с '.*?' и объединить все с | - но это может привести к ужасно длинному образцу RE в результате, потому чтоколичество перестановок N элементов равно N! («N factorial» - например, для N, равного 4, перестановки 4 * 3 * 2 * 1 == 24).Поэтому производительность может легко пострадать, если число элементов в списке не очень велико, очень мало.

Для более общего решения проблемы "сопоставить каждый элемент в произвольном порядке"(если это то, что вам нужно), один с производительностью и объемом памяти, который все еще приемлем для прилично больших длин списка, вам нужно отказаться от цели заставить все это работать с одним объектом RE, и ввести некоторую логику вmix - например, составьте список объектов RE с relist=[re.compile(p) for p in list_patterns] и отметьте «они все соответствуют строке s, в любом порядке» с all(r.search(s) for r in relist) или подобным.

Конечно, есливам нужно, чтобы этот последний подход работал «совместимым с утиной типизацией» с реальными объектами RE, это не сложно, например, если все, что вам нужно, это метод search, который возвращает логический результат (так как возвращает объект соответствия)"не имеет смысла) ...:

class relike(object):
    def __init__(self, list_patterns):
        self.relist = [re.compile(p) for p in list_patterns]
    def search(self, s):
        return all(r.search(s) for r in relist)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...