2017-06-13 16 views
0

我有多個(> 30)編譯的正則表達式的匹配和替換python 3中的多個字符串的有效方法?

regex_1 = re.compile(...) 
regex_2 = re.compile(...) 
#... define multiple regex's 
regex_n = re.compile(...) 

我然後有一個函數,它接受一個text並替換一些使用正則表達式的上述中的每一個和所述re.sub方法其詞語如下

def sub_func(text): 
    text = re.sub(regex_1, "string_1", text) 
    # multiple subsitutions using all regex's ... 
    text = re.sub(regex_n, "string_n", text) 

    return text 

問題:是否有更有效的方法來進行這些替換?

正則表達式無法從其當前形式進行概括或簡化。

我覺得每次重新分配text的值對於每個正則表達式都是相當慢的,因爲對於每次重新分配,該函數只替換整個text中的一個或兩個字。另外,由於我必須爲多個文檔執行此操作,因此這會降低速度。

在此先感謝!

+1

如果這些替換是相互排斥的,那麼**可能會發現執行're.sub(re.compile(「pattern1 | pattern2 | ...」),function_that_handles_match,text)會更快。 (當然,未經測試的假設:) –

+0

@Pythonista如果他想爲每個正則表達式替換一個單獨的字符串,它將不起作用 – victor

+1

當你開始命名變量'xxx_1','xxx_2'等等時,這是一個符號你真的想把這些收集到一個列表中。使其更容易添加或重新排序,並且遍歷列表比複製/粘貼'do_this_to(xxx_1)更簡單; do_this_to(XXX_2); do_this_to(xxx_2a_which_i_needed_between_2_and_3_but_didnt_want_to_renumber_everything); do_this_to(XXX_3);等等。 – PaulMcG

回答

3

重新分配一個值在Python中需要一段時間。與C語言不同,變量更多地是「名稱標籤」。因此,改變名稱標籤指向的時間非常短。

如果他們是常量字符串,我將它們收集到一個元組:

regexes = (
    (regex_1, 'string_1'), 
    (regex_2, 'string_2'), 
    (regex_3, 'string_3'), 
    ... 
) 

,然後在功能,只需遍歷列表:

def sub_func_2(text): 
    for regex, sub in regexes: 
     text = re.sub(regex, sub, text) 
    return text 

但如果你的正則表達式實際上是名稱爲regex_1,regex_2等,它們可能應該直接定義在某種列表中。

另外請注意,如果你正在做替換像'cat' - >'dog',在str.replace()方法可能會更容易(text = text.replace('cat', 'dog')),它可能會更快。


如果你的字符串是非常長,再使其從頭開始用正則表達式可能需要很長時間。這是在評論中提到的可能是@Oliver Charlesworth's方法的實現:

# Instead of this: 
regexes = (
    ('1(1)', '$1i'), 
    ('2(2)(2)', '$1a$2'), 
    ('(3)(3)3', '$1a$2') 
) 


# Merge the regexes: 
regex = re.compile('(1(1))|(2(2)(2))|((3)(3)3)') 
substitutions = (
    '{1}i', '{1}a{2}', '{1}a{2}' 
) 

# Keep track of how many groups are in each alternative 
group_nos = (1, 2, 2) 

cumulative = [1] 
for i in group_nos: 
    cumulative.append(cumulative[-1] + i + 1) 
del i 
cumulative = tuple(zip(substitutions, cumulative)) 

def _sub_func(match): 
    iter_ = iter(cumulative) 
    for sub, x in iter_: 
     if match.group(x) is not None: 
      return sub.format(*map(match.group, range(x, next(iter_)[1]))) 

def sub_func(text): 
    return re.sub(regex, _sub_func, text) 

但是,這打破了,如果你有,你需要替換重疊文本。

+4

我不認爲OP是擔心分配參考所需的時間;而是需要30次獨立的字符串替換(需要重建字符串30次)。 –

+0

感謝@Artyer,它真的可以清理我的代碼,因爲它可以讓我不必重複代碼(定義正則表達式,然後也可以在函數中逐個替換單詞)。元組for循環方法更加簡潔。由於正則表達式選出了非常具體的實體,所以不可能將它們推廣到更遠的地方。此外,字符串替換都是不同的,所以我不能用一個字符串替換它們。再次感謝! – killerT2333

0

我們可以通過一個函數來re.sub REPL參數

簡化至3的正則表達式爲了更容易理解

假設regex_1,regex_2和regex_3將是111222和333分別。然後,regex_replace將成爲將被替換使用的列表控制字符串,按照regex_1,regex_2和regex_3的順序。

  • regex_1將取代將「一」
  • regex_2與「二」等

不知道多少,這會雖然提高了運行時間,給更換一個嘗試

import re 
regex_x = re.compile('(111)|(222)|(333)') 
regex_replace = ['one', 'two', 'three'] 

def sub_func(text): 
    return re.sub(regex_x, lambda x:regex_replace[x.lastindex-1], text) 

>>> sub_func('testing 111 222 333') 
>>> 'testing one two three' 
相關問題