我有一个类似
的模式列表list_patterns = [': error:', ': warning:', 'cc1plus:', 'undefine reference to']
我想做的是生成一个所有这些联合的联合,产生一个匹配list_patterns
中每个元素的正则表达式[但可能不匹配任何不在list_patterns中的任何内容 - msw]
re.compile(list_patterns)
这可能吗?
答案 0 :(得分:10)
有几种方法可以做到这一点。最简单的是:
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()
传递每个模式来转义任何正则表达式特殊字符。
现在使用哪一个取决于您的模式列表。它们是正则表达式,因此可以假设有效吗?如果是这样,第一个可能是合适的。如果它们是字符串,请使用第二种方法。
对于第一个,它变得更复杂,但是因为通过连接几个正则表达式,您可能会更改分组并产生其他意外的副作用。
答案 1 :(得分:2)
list_regexs = [re.compile(x) for x in list_patterns]
答案 2 :(得分:1)
您想要一个匹配列表中任何项目的模式吗?那不就是:
': error:|: warning:|cc1plus:|undefine reference to'?
或者,在Python代码中:
re.compile("|".join(list_patterns))
答案 3 :(得分:1)
怎么样
ptrn = re.compile('|'.join(re.escape(e) for e in list_patterns))
请注意使用re.escape()
以避免因某些字符串中存在()[] |。+ *等字符而导致的意外后果。假设你想要那个,否则跳过escape()
。
这也取决于你打算如何'消费'那个表达 - 它只是为了搜索一个匹配还是你想收回匹配的组?
答案 4 :(得分:1)
Cletus给出了一个非常好的答案。但是,如果要匹配的其中一个字符串可能是另一个字符串的子字符串,那么您应该首先对字符串进行反向排序,以便最短匹配不会遮挡较长的字符串。
如果像亚历克斯所说的那样,原始海报想要他实际要求的东西,那么比使用排列更容易解决的问题可能是:
(... )
。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) )
答案 5 :(得分:0)
匹配的正则表达式 列表中的每个元素
我看到你已经得到了几个答案,基于这样的假设:“匹配列表中的每个元素”你实际上意味着匹配列表中的任何元素“(问题中的答案基于|
”或“正则表达式的运算符”。
如果你确实想要一个RE匹配列表中的每个元素(而不是任何一个这样的元素),那么你可能想要按照列表给出的相同顺序匹配它们他们(简单),或任何顺序(硬)。
对于有序匹配,'.*?'.join(list_patterns)
应该很好地为您服务(如果项目确实被视为RE模式 - 如果它们被视为文字字符串而不是'.*?'.join(re.escape(p) for p list_patterns)
)。
对于任何订单匹配,正则表达式本身不提供直接支持。您可以获取列表的所有排列(例如,使用itertools.permutations
),使用'.*?'
将每个排列连接起来,并将整个加入|
- 但这会产生非常长的RE结果是模式,因为N
项的排列数是N!
(“N因子” - 例如,对于N等于4,排列是4 * 3 * 2 * 1 == 24
)。因此,除非已知列表中的项目数量非常非常小,否则性能可能很容易受到影响。
对于“以任意顺序匹配每个项目”问题的更一般的解决方案(如果这是你需要的),一个性能和内存占用仍然可以接受的大量列表,你需要放弃使一个RE对象全部工作的目标,并在混合中注入一些逻辑 - 例如,使用relist=[re.compile(p) for p in list_patterns]
制作RE对象列表,并检查“它们都匹配字符串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)