繁体   English   中英

Python:定义正则表达式的并集

[英]Python: defining a union of regular expressions

我有一个类似的模式列表

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

我想要做的是生成一个所有这些联合的联合,产生一个匹配list_patterns中的每个元素的正则表达式[但可能不匹配任何不在list_patterns中的任何内容 - msw]

re.compile(list_patterns)

这可能吗?

有几种方法可以做到这一点。 最简单的是:

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()传递每个模式来转义任何正则表达式特殊字符。

现在使用哪一个取决于您的模式列表。 它们是正则表达式,因此可以假设有效吗? 如果是这样,第一个可能是合适的。 如果它们是字符串,请使用第二种方法。

对于第一个,它变得更复杂,但是因为通过连接几个正则表达式,您可能会更改分组并具有其他意外的副作用。

list_regexs = [re.compile(x) for x in list_patterns]

您想要一个匹配列表中任何项目的模式吗? 那不就是:

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

或者,在Python代码中:

re.compile("|".join(list_patterns))

怎么样

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

注意使用re.escape()来避免因某些字符串中存在像()[] |。+ *等字符而产生的意外后果。 假设你想要那个,否则跳过escape()

这也取决于你打算如何'消费'那个表达 - 它只是为了搜索一个匹配还是你想收回匹配的组?

克莱普斯给出了一个非常好的答案。 但是,如果要匹配的其中一个字符串可能是另一个字符串的子字符串,那么您可以先对字符串进行反向排序,以便最短匹配不会遮挡较长的字符串。

如果,正如亚历克斯所说,原始海报想要他实际要求的东西,那么比使用排列更容易处理的解决方案可能是:

  • 删除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) )

一个匹配列表中每个元素的正则表达式

我看你已经有了基于这样的假设,通过“列表中的每个元素相匹配”你实际上意味着“ 任何元素匹配列表”(在问题的答案是基于几个答案|经常“或”运算符表达式)。

如果你确实想要一个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 ,以任何顺序“with 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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM