webdevqa.jp.net

複数の正規表現パターンを代替演算子と照合しますか?

Python Regexを使用して小さな問題に遭遇しました。

これが入力だとしましょう:

_(zyx)bc
_

私が達成しようとしているのは、単一の一致として括弧の間にあるものを取得し、個々の一致として外側の文字を取得することです。望ましい結果は次のようになります。

_['zyx','b','c']
_

マッチの順序は守られるべきです。

私はPython 3.3でこれを取得しようとしましたが、正しい正規表現を理解できないようです。今のところ私は持っています:

_matches = findall(r'\((.*?)\)|\w', '(zyx)bc')
_

print(matches)は以下を生成します:

_['zyx','','']
_

私が間違っていることはありますか?

12
Julian Laval

re.findallのドキュメントから:

パターンに1つ以上のグループが存在する場合は、グループのリストを返します。パターンに複数のグループがある場合、これはタプルのリストになります。

正規表現が文字列に3回一致している間、(.*?)グループは2番目の2つの一致では空です。正規表現の他の半分の出力が必要な場合は、2番目のグループを追加できます。

>>> re.findall(r'\((.*?)\)|(\w)', '(zyx)bc')
[('zyx', ''), ('', 'b'), ('', 'c')]

または、すべてのグループを削除して、文字列の単純なリストを再度取得することもできます。

>>> re.findall(r'\(.*?\)|\w', '(zyx)bc')
['(zyx)', 'b', 'c']

ただし、括弧を手動で削除する必要があります。

12

re.DEBUGを使用して出力を見てみましょう。

branch 
  literal 40 
  subpattern 1 
    min_repeat 0 65535 
      any None 
  literal 41 
or
  in 
    category category_Word

そこにはsubpatternが1つしかありませんが、re.findallは、存在する場合にのみsubpatternsを引き出します!

a = re.findall(r'\((.*?)\)|(.)', '(zyx)bc',re.DEBUG); a
[('zyx', ''), ('', 'b'), ('', 'c')]
branch 
  literal 40 
  subpattern 1 
    min_repeat 0 65535 
      any None 
  literal 41 
or
  subpattern 2 
    any None

より良い。 :)

これを、希望する形式にする必要があります。

[i[0] if i[0] != '' else i[1] for i in a]
['zyx', 'b', 'c']
3

ドキュメントではグループの扱いについて特別に言及しているため、括弧で囲まれたパターンの周りにグループを配置しないでください。すべてが得られますが、一致したデータから括弧を自分で削除する必要があります。

>>> re.findall(r'\(.+?\)|\w', '(zyx)bc')
['(zyx)', 'b', 'c']

または、より多くのグループを使用し、結果のタプルを処理して、目的の文字列を取得します。

>>> [''.join(t) for t in re.findall(r'\((.+?)\)|(\w)', '(zyx)bc')]
>>> ['zyx', 'b', 'c']
1
Ned Batchelder
In [108]: strs="(zyx)bc"

In [109]: re.findall(r"\(\w+\)|\w",strs)
Out[109]: ['(zyx)', 'b', 'c']

In [110]: [x.strip("()") for x in re.findall(r"\(\w+\)|\w",strs)]
Out[110]: ['zyx', 'b', 'c']
1

他の回答では、必要な結果を得る方法が示されていますが、括弧を手動で削除するという追加のステップがあります。正規表現でルックアラウンドを使用する場合、括弧を手動で削除する必要はありません。

>>> import re
>>> s = '(zyx)bc'
>>> print (re.findall(r'(?<=\()\w+(?=\))|\w', s))
['zyx', 'b', 'c']

説明:

(?<=\() // lookbehind for left parenthesis
\w+     // all characters until:
(?=\))  // lookahead for right parenthesis
|       // OR
\w      // any character
1
alan