2017-02-15 13 views
1

私は以下のようなコードをいくつか持っています。ファイルの各行をいくつかのパターンで検索し、一致するパターンから文字列を抽出します。各行は、もしあれば、最大でも1つのパターンと一致するだけです。ファイルにはテキスト行だけがあり、行にはhight = 123、medium = 123、およびlow = 123があります。一例として、いくつかの不正なコードで下図のように私は、2番目の検索を行うことなしにマッチした部分を抽出することができればpython:一致するパターンを抽出するためのより良い方法は?

with open(file) as r: 
    for line in r: 
     if re.search('high=\d+', line): 
      p = re.search('high=(\d+)', line) 
      high = p.group(1) 
     elif re.search('medium=\d+', line): 
      p = re.search('medium=(\d+)', line) 
      medium = p.group(1) 
     elif re.search('low=\d+', line): 
      p = re.search('low=(\d+)', line) 
      low = p.group(1) 
     ... 

は今、私は思ったんだけど。検索されたパターンは、互いに非常に異なる可能性があります。ここでの問題は、re.search()がtrueを返した後で一致する部分を抽出する方法があるかどうかです。

with open(file) as r: 
    for line in r: 
     if re.search('high=(\d+)', line): 
      high = _.group(1) # invalid code, but looking for something like this. 
     elif re.search('medium=(\d+)', line): 
      medium = _.group(1) # invalid code 
     elif re.search('low=(\d+)', line): 
      low = _.group(1)  # invalid code 
     ... 

注意これは私が望んでいたものではありませんが、それは私が望むものではありません。

with open(file) as r: 
    for line in r: 
     m = re.search('high=(\d+)', line) 
     if m: 
      high = m.group(1) 
     else: 
      m = re.search('medium=(\d+)', line) 
      if m: 
       medium = m.group(1) 
      else: 
       m = re.search('low=(\d+)', line) 
       if m: 
        low = m.group(1) 
     ... 

私は次のような、最初のパターンをコンパイルしようとしたが、私はエラーだ「NameError:定義されていない名前 『_』」を。私はpython2とpython3の両方でこれを試しました。 _.group(1)(いくつかのケースではうまくいきました)ではいくつかの特殊な振る舞いがあります。私は別の投稿で問題を提起するかもしれません。

h = re.compile('hight=(\d+)') 
m = re.compile('medium=(\d+)') 
l = re.compile('low=(\d+)') 

with open(file) as r: 
    for line in r: 
     if h.search(line): 
      high = _.group(1) 
     elif m.search(line): 
      medium = _.group(1) 
     elif l.search(line): 
      low = _.group(1) 
     ... 
+0

入力の例とそれから生成すると期待されるものがあれば助けになります。 – naktinis

+0

@naktinisありがとうございます。私はいくつかの説明を追加しました。実際には質問は非常に簡単です。 re.search()がtrueを返した後、一致するパターンの一部を取得する方法はありますか? Perlではこれを行うことができます(一致する部分はグローバル変数に保存されます)。 – Shiping

+1

Pythonにはグローバル変数への自動割り当てがありません。ラッパー関数を簡単に書くことができますが、言語に組み込まれていません。 –

答えて

2

_最後に実行されたステートメントの結果を保持してみてください。これは、プログラムの文脈における単なる普通の変数です。

したがって、再度検索したくない場合は、3番目のコード例のように、一致オブジェクトを保存する必要があります。あなたがIFSをネスト回避したい場合

、あなたは継続使用することができます。

with open(file) as r: 
    for line in r: 
     m = re.search('high=(\d+)', line) 
     if m: 
      high = m.group(1) 
      continue 
     m = re.search('medium=(\d+)', line) 
     if m: 
      medium = m.group(1) 
      continue 
     m = re.search('low=(\d+)', line) 
     if m: 
      low = m.group(1) 
      continue 
     ... 

編集、あなたのコメントに答えるために:

Pythonであなたが欲しいものを行うには、一般的な方法はありませんが:

  • あなたは、Perlでのように、変数に結果のいずれかの自動割り当てを持っていない

  • あなたはXXX = YYY場合

    を書き込むことはできません。

    :代わりに==

    けれどもの誤って=書き込みを避けるために

、それを行うための一つの方法は常にあります

import re 


class Matcher: 
    def __init__(self, pattern): 
     self._pattern = pattern 
     self._compiled_pattern = re.compile(pattern) 
     self._match = None 

    def __str__(self): 
     return '<Matcher> %s, matching %s' % (self._pattern, self._match) 

    # match and search apply on the regex, and return the match object 
    def match(self, string): 
     self._match = self._compiled_pattern.match(string) 
     return self._match 

    def search(self, string): 
     self._match = self._compiled_pattern.search(string) 
     return self._match 

    # Other methods apply to the match object 
    def __getattr__(self, attr): 
     return getattr(self._match, attr) 



if __name__ == '__main__': 

    # instead of m = re.compile(...) 
    m = Matcher(r'(high)=(\d+)') 

    lines = ['high=4', 'nothing here'] 


    for line in lines: 
     # you can use search and match just like on the re object 
     if m.search(line): 
      # then you can use all methods of Match objects 
      print(m.groups()) 
      print(m.group(1), m.group(2)) 
      print(m.span()) 

だから、あなたが望むように振る舞うようです!

+0

ありがとうございます。これは確かに動作します。しかし、私は2番目のコード例に示すような代替案があるかどうかを知りたがっています。明らかにPythonにはこのような機能がありません。 – Shiping

+0

@Shiping - Pythonには機能がありませんが、自分で追加するのは簡単です。ここに示すクラスベースの実装はより正式なものであり、より適切なものもあります。しかし、単にあなた自身のグローバル変数を使い、非常に短い関数を書いて検索を行い、グローバルを更新することができます。 –

+0

ありがとうございます。私はPythonにそれが組み込まれているようなものがあることを望んでいましたが、私が望むように動作します。 – Shiping

2

あなたは、インタラクティブシェルで作業するとき、これは

import re 
r = re.compile("(high|medium|low)=(\d+)") 
with open(file) as f: 
    for line in f: 
     match = r.search(line) 
     if not match: 
      continue 
     lvl, val = match.groups() 
     if lvl == "high": 
      high = val 
     elif lvl == "medium": 
      medium = val 
     elif lvl == "low": 
      low = val 
+0

ありがとうございます。あなたが投稿した内容は、自分のコードで示したケースでうまくいくはずです。しかし、私が探しているのは、re.search()が何かをテストすることなくtrueを返した後、マッチしたパターンを抽出するもっと一般的な方法です。 – Shiping

+0

@Shiping 're.search'は' Match'オブジェクトを返します。ブール値ではありません。上記のコードは、 'match'を' search'に置き換えても動作します。テストして抽出したい場合は、上の同じコードを 'try..except'するか、' re.search'が返す 'Match'オブジェクトを代入し、' None'かどうかを調べることができます。 – adifire

+0

@adifire - あなたの編集がOPが探しているものに近いとは思わない。実際それはもっと悪いかもしれません。主要な質問でPerlに関するコメントを参照してください。 –

関連する問題