簡體   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