Python Regexを使用して小さな問題に遭遇しました。
これが入力だとしましょう:
_(zyx)bc
_
私が達成しようとしているのは、単一の一致として括弧の間にあるものを取得し、個々の一致として外側の文字を取得することです。望ましい結果は次のようになります。
_['zyx','b','c']
_
マッチの順序は守られるべきです。
私はPython 3.3でこれを取得しようとしましたが、正しい正規表現を理解できないようです。今のところ私は持っています:
_matches = findall(r'\((.*?)\)|\w', '(zyx)bc')
_
print(matches)
は以下を生成します:
_['zyx','','']
_
私が間違っていることはありますか?
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']
ただし、括弧を手動で削除する必要があります。
re.DEBUG
を使用して出力を見てみましょう。
branch
literal 40
subpattern 1
min_repeat 0 65535
any None
literal 41
or
in
category category_Word
そこにはsubpattern
が1つしかありませんが、re.findall
は、存在する場合にのみsubpattern
sを引き出します!
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']
ドキュメントではグループの扱いについて特別に言及しているため、括弧で囲まれたパターンの周りにグループを配置しないでください。すべてが得られますが、一致したデータから括弧を自分で削除する必要があります。
>>> re.findall(r'\(.+?\)|\w', '(zyx)bc')
['(zyx)', 'b', 'c']
または、より多くのグループを使用し、結果のタプルを処理して、目的の文字列を取得します。
>>> [''.join(t) for t in re.findall(r'\((.+?)\)|(\w)', '(zyx)bc')]
>>> ['zyx', 'b', 'c']
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']
他の回答では、必要な結果を得る方法が示されていますが、括弧を手動で削除するという追加のステップがあります。正規表現でルックアラウンドを使用する場合、括弧を手動で削除する必要はありません。
>>> 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