Python の re モジュールを使用して、名前付きグループの任意の順序なしセットを一度に取得することは可能ですか?

StackOverflow https://stackoverflow.com/questions/2187931

  •  25-09-2019
  •  | 
  •  

質問

これは、いくつかの問題に対して非常に便利です。

>>> re.search('(?P<b>.b.).*(?P<i>.i.)', 'abcdefghijk').groupdict()
{'i': 'hij', 'b': 'abc'}

しかし、事前にどのような順序が予想されるかわからない場合はどうすればよいでしょうか?

[アップデート]

たとえば、未知の順序の文字を含む入力変数があり、たまたま 'b' が 'i' の後に来るとします。「.B」についてグループを参照できるようになりたいです。そして私。'入力var。したがって、次のようなことができればいいのですが、それが可能かどうかはわかりません。

>>> re.search('(?P<b>.b.)|(?P<i>.i.)', unknown_order_alphabet_str).groupdict()
{'i': 'hij', 'b': 'abc'}

[更新終了]

いろいろ検索して頭を悩ませましたが、良い見込み客を生み出すことができません。おそらくこれを行う唯一の方法は、グループごとに文字列全体を 1 回スキャンすることなので、この機能は存在しないだろうと推測しています (もちろん、代わりにループで実行することもできます)。それについて言わなければならなかった。

ご協力いただきありがとうございます、
ジョシュ

役に立ちましたか?

解決

を使用する垂直REパターンのバー(「または」)、および関心のすべての一致オブジェクトを取得するfinditer:それぞれがその試合に関与していないグループの値としてgroupdictNoneを持つことになりますし、あなたが「マージすることができます「あなたが好むようdictsます。

例えば、

import re

def mergedgroupdict(pattern, thestring):
  there = re.compile(pattern)
  result = {}
  for mo in there.finditer(thestring):
    d = mo.groupdict()
    for k in d:
      if k not in result and d[k] is not None:
        result[k] = d[k]
  return result

これは、パターン内の各名前付きグループのための第1の実際の一致を選択するだけでマージ戦略を使用します。今、例えば

>>> mergedgroupdict('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk')
{'i': 'hij', 'b': 'abc'}
>>> mergedgroupdict('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk'[::-1])
{'i': 'jih', 'b': 'cba'}

おそらく私が正しくあなたの質問を解釈する場合は、希望通ります。

他のヒント

>>> [m.groupdict() for m in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk')]
[{'i': None, 'b': 'abc'}, {'i': 'hij', 'b': None}]
あなたがされていない1チェック多くのグループを持っている場合Noneは退屈かもしれませんが、仕事の罰金に思えます。

この文字列内のすべての.b.とすべて.i.の一致を検索します。あなたがなりたかった場合は必ずそれは一つは、あなたがあまりにも、手動でそれを確認する必要がありますそれぞれのいずれかを見つけます。

私が得ることができる最も近いがこれです:

>>> [match.groupdict() for match in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk')]
[{'i': None, 'b': 'abc'}, {'i': 'hij', 'b': None}]
あなたは辞書を組み合わせてどのように、あなたが複数の一致を期待しているかどうかによって異なります。あなたは一つだけがそれぞれに合わせたい場合は、あなたが行うことができます:

>>> results = {}
>>> for match in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijk'):
...     results.update(dict((k,v) for k, v in match.groupdict().iteritems() if v is not None))
... 
>>> results
{'i': 'hij', 'b': 'abc'}

または複数の一致のために

>>> results = defaultdict(lambda: [])
>>> for match in re.finditer('(?P<b>.b.)|(?P<i>.i.)', 'abcdefghijkabcdefghijk'):
...     for k, v in match.groupdict().iteritems():
...         if v is not None:
...             results[k].append(v)
... 
>>> results
defaultdict(<function <lambda> at 0x7f53d0992c08>, {'i': ['hij', 'hij'], 'b': ['abc', 'abc']})

必要のない方法は次のとおりです finditer 辞書の結合もありません:

>>> pat = re.compile(r'(?:.*?(?:(?P<b>.b.)|(?P<i>.i.))){2}')

>>> pat.search('abcdefghijk').groupdict()
{'i': 'hij', 'b': 'abc'}

>>> pat.search('aicdefghbjk').groupdict()
{'i': 'aic', 'b': 'hbj'}

これは各キャラクターを想定しています b そして i string 内に 1 回だけ出現する場合、それ以外の場合は次のようになります。

  • 文字の 1 つが欠けている可能性がある場合は、次を使用できます。 {,2} の代わりに {2}.
  • いずれかの文字が複数回出現する場合、検索では最初の 2 つの出現が取得されます。 どちらか それらのうち(たとえば、 b 2回も見つからない i まったく)。

ここでは、あまりにも初心者向けの読みやすい1回のスワイプでゲーム後半コーナーがあります:

>>> dict([(name, re.search(pattern, "abcdefghijk").group())
          for name, pattern in {"b": ".b.", "i": ".i"}.items()])  
{'b': 'abc', 'i': 'hij'}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top