何かが正規表現に一致するかどうかを確認したい場合は、一致する場合は、最初のグループを印刷します。
import re
match = re.match("(\d+)g", "123g")
if match is not None:
print match.group(1)
これは完全に衒学的ですが、中間のmatch
変数は少し面倒です。
Perlのような言語は、..のようなマッチグループ用の新しい$1
..$9
変数を作成することによってこれを行います。
if($blah ~= /(\d+)g/){
print $1
}
から このredditコメント 、
with re_context.match('^blah', s) as match:
if match:
...
else:
...
..これは面白いアイデアだと思ったので、簡単な実装を作成しました。
#!/usr/bin/env python2.6
import re
class SRE_Match_Wrapper:
def __init__(self, match):
self.match = match
def __exit__(self, type, value, tb):
pass
def __enter__(self):
return self.match
def __getattr__(self, name):
if name == "__exit__":
return self.__exit__
Elif name == "__enter__":
return self.__name__
else:
return getattr(self.match, name)
def rematch(pattern, inp):
matcher = re.compile(pattern)
x = SRE_Match_Wrapper(matcher.match(inp))
return x
return match
if __name__ == '__main__':
# Example:
with rematch("(\d+)g", "123g") as m:
if m:
print(m.group(1))
with rematch("(\d+)g", "123") as m:
if m:
print(m.group(1))
(この機能は、理論的には_sre.SRE_Match
オブジェクトにパッチを適用できます)
一致するものがなかった場合、with
ステートメントのコードブロックの実行をスキップできれば、これは簡単になります。
with rematch("(\d+)g", "123") as m:
print(m.group(1)) # only executed if the match occurred
..しかし、これは私が推測できることに基づいて不可能に思えます PEP 34
何か案は?私が言ったように、これは本当に些細な煩わしさであり、ほとんどコードゴルフになるほどです。
_Python 3.8
_を開始し、 代入式(PEP 572) (_:=
_演算子)を導入すると、条件値re.match(r'(\d+)g', '123g')
を変数に取り込むことができるようになります。 match
がNone
でないかどうかを確認し、条件の本体内で再利用するには、次のようにします。
_>>> if match := re.match(r'(\d+)g', '123g'):
... print(match.group(1))
...
123
>>> if match := re.match(r'(\d+)g', 'dddf'):
... print(match.group(1))
...
>>>
_
些細なことではないと思います。そのようなコードを頻繁に書いているのであれば、コードの周りに冗長な条件を散りばめる必要はありません。
これは少し奇妙ですが、イテレータを使用してこれを行うことができます。
import re
def rematch(pattern, inp):
matcher = re.compile(pattern)
matches = matcher.match(inp)
if matches:
yield matches
if __name__ == '__main__':
for m in rematch("(\d+)g", "123g"):
print(m.group(1))
奇妙なことに、反復していないものにイテレータを使用しています。条件に近く、一見すると、一致ごとに複数の結果が得られるように見える場合があります。
コンテキストマネージャがその管理対象関数を完全にスキップさせることができないのは奇妙に思えます。これは明示的に「with」のユースケースの1つではありませんが、自然な拡張のようです。
もう1つのNice構文は、次のようになります。
header = re.compile('(.*?) = (.*?)$')
footer = re.compile('(.*?): (.*?)$')
if header.match(line) as m:
key, value = m.group(1,2)
Elif footer.match(line) as m
key, value = m.group(1,2)
else:
key, value = None, None
グレンメイナードの解決策に基づいて、これを行う別の方法があります:
for match in [m for m in [re.match(pattern,key)] if m]:
print "It matched: %s" % match
グレンのソリューションと同様に、これは0(一致しない場合)または1(一致する場合)のいずれかを繰り返します。
サブは必要ありませんが、結果として整頓されていません。
これらの多くを1つの場所で行っている場合は、別の答えがあります。
import re
class Matcher(object):
def __init__(self):
self.matches = None
def set(self, matches):
self.matches = matches
def __getattr__(self, name):
return getattr(self.matches, name)
class re2(object):
def __init__(self, expr):
self.re = re.compile(expr)
def match(self, matcher, s):
matches = self.re.match(s)
matcher.set(matches)
return matches
pattern = re2("(\d+)g")
m = Matcher()
if pattern.match(m, "123g"):
print(m.group(1))
if not pattern.match(m, "x123g"):
print "no match"
Reと同じスレッドセーフで正規表現を1回コンパイルし、関数全体に対して単一の再利用可能なMatcherオブジェクトを作成すると、非常に簡潔に使用できます。これには、明らかな方法で逆にすることができるという利点もあります。イテレータを使用してそれを行うには、結果を反転するように指示するフラグを渡す必要があります。
ただし、関数ごとに1つの一致のみを実行している場合は、あまり役に立ちません。それよりも広いコンテキストでMatcherオブジェクトを保持する必要はありません。 Blixtのソリューションと同じ問題が発生します。
完璧な解決策ではありませんが、同じstrに対して複数の一致オプションを連鎖させることができます。
class MatchWrapper(object):
def __init__(self):
self._matcher = None
def wrap(self, matcher):
self._matcher = matcher
def __getattr__(self, attr):
return getattr(self._matcher, attr)
def match(pattern, s, matcher):
m = re.match(pattern, s)
if m:
matcher.wrap(m)
return True
else:
return False
matcher = MatchWrapper()
s = "123g";
if _match("(\d+)g", line, matcher):
print matcher.group(1)
Elif _match("(\w+)g", line, matcher):
print matcher.group(1)
else:
print "no match"
これは実際には見栄えがよくありませんが、次のように使用すると、getattr(object, name[, default])
組み込み関数から利益を得ることができます。
>>> getattr(re.match("(\d+)g", "123g"), 'group', lambda n:'')(1)
'123'
>>> getattr(re.match("(\d+)g", "X23g"), 'group', lambda n:'')(1)
''
印刷グループに一致する場合フローを模倣するには、次のようにfor
ステートメントを(ab)使用できます。
>>> for group in filter(None, [getattr(re.match("(\d+)g", "123g"), 'group', None)]):
print(group(1))
123
>>> for group in filter(None, [getattr(re.match("(\d+)g", "X23g"), 'group', None)]):
print(group(1))
>>>
もちろん、汚い仕事をするための小さな関数を定義することができます:
>>> matchgroup = lambda p,s: filter(None, [getattr(re.match(p, s), 'group', None)])
>>> for group in matchgroup("(\d+)g", "123g"):
print(group(1))
123
>>> for group in matchgroup("(\d+)g", "X23g"):
print(group(1))
>>>
この場合、with
を使用することが解決策ではないと思います。 BLOCK
部分(ユーザーが指定)で例外を発生させ、__exit__
メソッドがTrue
を返して例外を「飲み込む」必要があります。だからそれは決して良く見えないでしょう。
Perl構文に似た構文を選択することをお勧めします。独自の拡張re
モジュール(これをrex
と呼びます)を作成し、モジュール名前空間に変数を設定します。
if rex.match('(\d+)g', '123g'):
print rex._1
以下のコメントでわかるように、このメソッドはスコープセーフでもスレッドセーフでもありません。これを使用するのは、アプリケーションが将来マルチスレッド化されないこと、およびこれを使用しているスコープから呼び出された関数がalso同じ方法を使用します。
これが私の解決策です:
import re
s = 'hello world'
match = []
if match.append(re.match('w\w+', s)) or any(match):
print('W:', match.pop().group(0))
Elif match.append(re.match('h\w+', s)) or any(match):
print('H:', match.pop().group(0))
else:
print('No match found')
Elif句は必要な数だけ使用できます。
さらに良い:
import re
s = 'hello world'
if vars().update(match=re.match('w\w+', s)) or match:
print('W:', match.group(0))
Elif vars().update(match=re.match('h\w+', s)) or match:
print('H:', match.group(0))
else:
print('No match found')
appendとpdate return Noneの両方。したがって、すべての場合にまたは部分を使用して、式の結果を実際に確認する必要があります。
残念ながら、これはコードがトップレベルにある場合、つまり関数内にない場合にのみ機能します。
これが私がすることです:
def re_match_cond (match_ref, regex, text):
match = regex.match (text)
del match_ref[:]
match_ref.append (match)
return match
if __name__ == '__main__':
match_ref = []
if re_match_cond (match_ref, regex_1, text):
match = match_ref[0]
### ...
Elif re_match_cond (match_ref, regex_2, text):
match = match_ref[0]
### ...
Elif re_match_cond (match_ref, regex_3, text):
match = match_ref[0]
### ...
else:
### no match
### ...
つまり、リストを関数に渡して、参照渡しをエミュレートします。