2017-06-13 11 views
0

私は、複数の(> 30)コンパイルI次いでtextをとり、python 3で複数の文字列をマッチングして置き換える効率的な方法は?

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 
を次のように上記正規表現の一人一人と re.sub方法を用いて、その単語の一部を置換する機能を有する

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

正規表現の

質問:これらの交換をより効率的に行う方法はありますか?

正規表現を現在の形式から一般化または簡略化することはできません。

正規表現ごとに毎回textという値を再割り当てすると、再割り当てごとにtext全体の1つまたは2つの単語だけが関数に置き換えられます。また、私は複数のドキュメントでこれを行う必要があることを考えると、それは物事をさらに減速させます。

ありがとうございます!

+1

これらの置き換えが相互に排他的である場合、** re **(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_3); – PaulMcG

答えて

3

値を再割り当てすると、Pythonでは一定の時間がかかります。 Cのような言語とは異なり、変数は「名前タグ」のほうが多いです。したがって、名前タグが指し示すものを変更することは、ほとんど時間がかかりません。

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

しかし、あなたの正規表現は、実際にしている場合:リストだけを反復、あなたの関数で、その後

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

そして:彼らは定数文字列がある場合、私はタプルにそれらを集めるでしょう

regex_1regex_2などのように、おそらく何らかの並べ替えのリストに直接定義する必要があります。 >'dog'str.replace()方法は、(text = text.replace('cat', 'dog'))方が簡単な場合があります、そしてそれはおそらく速くなる -

また、あなたが'cat'のような置換を行っている場合は、注意してください。


あなたの文字列がある場合は正規表現と最初からそれを非常に長く、そして再作成するには、非常に長くかかることがあります。コメントで述べた@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、それは本当に私がコードを複製することから(私の関数で正規表現を定義し、次に単語を一つずつ置き換えることから)私を節約するので、私のコードをたくさんクリーンアップします。 tuple-forループのアプローチははるかに綺麗です。正規表現は非常に特定のエンティティを選ぶので、それをさらに一般化することはできませんでした。また、文字列の置換はすべて異なっているので、それらをすべて1つの文字列で置き換えることはできません。再度、感謝します! – killerT2333

0

我々はregex_1、regex_2、及びregex_3はそれぞれ111222及び333あろうと仮定理解を容易にするために3正規表現に

を簡素化re.sub REPL引数

に関数を渡すことができます。次に、regex_replaceは、regex_1、regex_2、およびregex_3の順番でreplaceに使用される文字列を保持するリストになります。regex_1が「1」

  • regex_2が
  • ない、これは、しかし、ランタイムを向上させることにしてみてください

    を与えるどのくらい確かに「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' 
      
    関連する問題