Python Language
正規表現(正規表現)
サーチ…
前書き
Pythonはre
モジュールを通して正規表現を利用可能にします。
正規表現は、部分文字列の一致の規則として解釈される文字の組み合わせです。例えば、表現'amount\D+\d+'
ワードによって構成される任意の文字列一致するamount
などの1つ以上の非桁によって分離された積分数: amount=100
、 amount is 3
、 amount is equal to: 33
など
構文
直接正規表現
re.match(パターン、文字列、フラグ= 0)#Out:文字列の先頭に一致するパターンまたはなし
re.search(pattern、string、flag = 0)#Out:文字列内のパターンとの一致またはなし
re.findall(pattern、string、flag = 0)#Out:stringまたは[]内のpatternのすべての一致のリスト
re.finditer(pattern、string、flag = 0)#Out:re.findallと同じですが、iteratorオブジェクトを返します。
(パターン、置換、文字列、フラグ= 0)#Out:パターンの代わりに置換(文字列または関数)を持つ文字列
プリコンパイルされた正規表現
precompiled_pattern = re.compile(パターン、フラグ= 0)
precompiled_pattern.match(string)#Out:文字列の先頭に一致するかNone
precompiled_pattern.search(string)#Out:文字列内のどこにでも一致するか、Noneになります。
precompiled_pattern.findall(string)#Out:一致するすべての部分文字列のリスト
precompiled_pattern.sub(文字列/パターン/関数、文字列)#Out:置き換えられた文字列
文字列の先頭に一致する
re.match()
の最初の引数は正規表現で、2番目の引数は一致する文字列です:
import re
pattern = r"123"
string = "123zzb"
re.match(pattern, string)
# Out: <_sre.SRE_Match object; span=(0, 3), match='123'>
match = re.match(pattern, string)
match.group()
# Out: '123'
パターン変数は文字列が生の文字列リテラルであることを示すr
接頭文字列であることがわかります。
生の文字列リテラルは、文字列リテラルとは少し異なる構文を持っています。つまり、生の文字列リテラルのバックスラッシュ\
は "バックスラッシュ"を意味し、改行( \n
)などのエスケープシーケンスをエスケープするバックラッシュを倍増する必要はありません。 、タブ( \t
)、バックスペース( \
)、フォームフィード( \r
)などがあります。通常の文字列リテラルでは、各バックスラッシュは、エスケープシーケンスの開始とみなされることを避けるために、2倍にする必要があります。
したがって、 r"\n"
は\
とn
2文字の文字列です。正規表現パターンもバックスラッシュを使用します。たとえば、 \d
は任意の数字文字を表します。生の文字列( r"\d"
)を使用して文字列( "\\d"
)を二重にエスケープする必要はあり"\\d"
。
例えば:
string = "\\t123zzb" # here the backslash is escaped, so there's no tab, just '\' and 't'
pattern = "\\t123" # this will match \t (escaping the backslash) followed by 123
re.match(pattern, string).group() # no match
re.match(pattern, "\t123zzb").group() # matches '\t123'
pattern = r"\\t123"
re.match(pattern, string).group() # matches '\\t123'
マッチングは文字列の先頭からのみ実行されます。どこでも一致させたい場合は、代わりにre.search
を使います:
match = re.match(r"(123)", "a123zzb")
match is None
# Out: True
match = re.search(r"(123)", "a123zzb")
match.group()
# Out: '123'
検索
pattern = r"(your base)"
sentence = "All your base are belong to us."
match = re.search(pattern, sentence)
match.group(1)
# Out: 'your base'
match = re.search(r"(belong.*)", sentence)
match.group(1)
# Out: 'belong to us.'
検索は、 re.match
とは異なり、文字列のどこでも実行されます。 re.findall
使用することもできre.findall
。
文字列の先頭( ^
使用)で検索することもできます。
match = re.search(r"^123", "123zzb")
match.group(0)
# Out: '123'
match = re.search(r"^123", "a123zzb")
match is None
# Out: True
文字列の最後に( $
使用)、
match = re.search(r"123$", "zzb123")
match.group(0)
# Out: '123'
match = re.search(r"123$", "123zzb")
match is None
# Out: True
または両方を使用します( ^
と$
両方を使用します)。
match = re.search(r"^123$", "123")
match.group(0)
# Out: '123'
グルーピング
グループ化はカッコで行います。 group()
呼び出すと、カッコで囲まれたサブグループに一致する文字列が返されます。
match.group() # Group without argument returns the entire match found
# Out: '123'
match.group(0) # Specifying 0 gives the same result as specifying no argument
# Out: '123'
group()
に引数を与えて、特定のサブグループをフェッチすることもできます。
ドキュメントから:
引数が1つの場合、結果は単一の文字列になります。複数の引数がある場合、その結果は引数ごとに1つの項目を含むタプルです。
一方、 groups()
を呼び出すと、サブグループを含むタプルのリストが返されます。
sentence = "This is a phone number 672-123-456-9910"
pattern = r".*(phone).*?([\d-]+)"
match = re.match(pattern, sentence)
match.groups() # The entire match as a list of tuples of the paranthesized subgroups
# Out: ('phone', '672-123-456-9910')
m.group() # The entire match as a string
# Out: 'This is a phone number 672-123-456-9910'
m.group(0) # The entire match as a string
# Out: 'This is a phone number 672-123-456-9910'
m.group(1) # The first parenthesized subgroup.
# Out: 'phone'
m.group(2) # The second parenthesized subgroup.
# Out: '672-123-456-9910'
m.group(1, 2) # Multiple arguments give us a tuple.
# Out: ('phone', '672-123-456-9910')
名前付きグループ
match = re.search(r'My name is (?P<name>[A-Za-z ]+)', 'My name is John Smith')
match.group('name')
# Out: 'John Smith'
match.group(1)
# Out: 'John Smith'
名前だけでなくインデックスによっても参照できるキャプチャグループを作成します。
非捕捉グループ
(?:)
を使用するとグループが作成されますが、グループは取得されません。つまり、それをグループとして使うことはできますが、あなたの "グループスペース"は汚染されません。
re.match(r'(\d+)(\+(\d+))?', '11+22').groups()
# Out: ('11', '+22', '22')
re.match(r'(\d+)(?:\+(\d+))?', '11+22').groups()
# Out: ('11', '22')
この例では一致して11+22
や11
ではなく11+
。これは、 +
記号と第2項がグループ化されているためです。一方、 +
記号は取り込まれません。
特殊文字をエスケープする
特殊文字(文字クラスの括弧[
と]
ようなもの)は文字通り一致しません:
match = re.search(r'[b]', 'a[b]c')
match.group()
# Out: 'b'
特殊文字をエスケープすることで、それらを文字通り一致させることができます:
match = re.search(r'\[b\]', 'a[b]c')
match.group()
# Out: '[b]'
re.escape()
関数を使ってこれを行うことができます:
re.escape('a[b]c')
# Out: 'a\\[b\\]c'
match = re.search(re.escape('a[b]c'), 'a[b]c')
match.group()
# Out: 'a[b]c'
re.escape()
関数はすべての特殊文字をエスケープするので、ユーザー入力に基づいて正規表現を作成する場合に便利です。
username = 'A.C.' # suppose this came from the user
re.findall(r'Hi {}!'.format(username), 'Hi A.C.! Hi ABCD!')
# Out: ['Hi A.C.!', 'Hi ABCD!']
re.findall(r'Hi {}!'.format(re.escape(username)), 'Hi A.C.! Hi ABCD!')
# Out: ['Hi A.C.!']
置換
文字列の置換
re.sub(r"t[0-9][0-9]", "foo", "my name t13 is t44 what t99 ever t44")
# Out: 'my name foo is foo what foo ever foo'
グループ参照の使用
少数のグループの置換えは、次のようにして行うことができます。
re.sub(r"t([0-9])([0-9])", r"t\2\1", "t13 t19 t81 t25")
# Out: 't31 t91 t18 t52'
ただし、 '10'のようなグループIDを作成した場合、 これは機能しません 。 \10
は 'ID番号1の後ろに0'と読み込まれます。したがって、より具体的で\g<i>
表記を使用する必要があります。
re.sub(r"t([0-9])([0-9])", r"t\g<2>\g<1>", "t13 t19 t81 t25")
# Out: 't31 t91 t18 t52'
置換関数の使用
items = ["zero", "one", "two"]
re.sub(r"a\[([0-3])\]", lambda match: items[int(match.group(1))], "Items: a[0], a[1], something, a[2]")
# Out: 'Items: zero, one, something, two'
すべて重複しない一致を検索する
re.findall(r"[0-9]{2,3}", "some 1 text 12 is 945 here 4445588899")
# Out: ['12', '945', '444', '558', '889']
"[0-9]{2,3}"
前のr
は、Pythonが文字列をそのまま解釈するように指示することに注意してください。 「未処理の」文字列として扱います。
また、使用することができますre.finditer()
同じように動作しているre.findall()
が、とイテレータを返すSRE_Match
代わりに文字列のリストのオブジェクト:
results = re.finditer(r"([0-9]{2,3})", "some 1 text 12 is 945 here 4445588899")
print(results)
# Out: <callable-iterator object at 0x105245890>
for result in results:
print(result.group(0))
''' Out:
12
945
444
558
889
'''
プリコンパイルされたパターン
import re
precompiled_pattern = re.compile(r"(\d+)")
matches = precompiled_pattern.search("The answer is 41!")
matches.group(1)
# Out: 41
matches = precompiled_pattern.search("Or was it 42?")
matches.group(1)
# Out: 42
パターンをコンパイルすると、後でプログラムで再利用できます。しかし、Pythonは最近使用された式( docs 、 SOの答え )をキャッシュしているので、 "正規表現をコンパイルすることについて一度にいくつかの正規表現しか使用しないプログラムは心配する必要はありません" 。
import re
precompiled_pattern = re.compile(r"(.*\d+)")
matches = precompiled_pattern.match("The answer is 41!")
print(matches.group(1))
# Out: The answer is 41
matches = precompiled_pattern.match("Or was it 42?")
print(matches.group(1))
# Out: Or was it 42
これはre.match()で使用できます。
許可されている文字のチェック
文字列に特定の文字セット(この場合はaz、AZおよび0-9)のみが含まれていることを確認したい場合は、このようにすることができます。
import re
def is_allowed(string):
characherRegex = re.compile(r'[^a-zA-Z0-9.]')
string = characherRegex.search(string)
return not bool(string)
print (is_allowed("abyzABYZ0099"))
# Out: 'True'
print (is_allowed("#*@#$%^"))
# Out: 'False'
式の行を[^a-zA-Z0-9.]
から[^a-z0-9.]
に変更して、大文字を禁止することもできます。
部分的なクレジット: http : //stackoverflow.com/a/1325265/2697955
正規表現を使用して文字列を分割する
正規表現を使用して文字列を分割することもできます。例えば、
import re
data = re.split(r'\s+', 'James 94 Samantha 417 Scarlett 74')
print( data )
# Output: ['James', '94', 'Samantha', '417', 'Scarlett', '74']
フラグ
特別な場合には、正規表現の動作を変更する必要があります。これはフラグを使用して行われます。フラグは、 flags
キーワードまたは式の中で直接2通りの方法で設定できます。
Flagsキーワード
以下はre.search
の例re.search
が、 re
モジュールのほとんどの関数で動作します。
m = re.search("b", "ABC")
m is None
# Out: True
m = re.search("b", "ABC", flags=re.IGNORECASE)
m.group()
# Out: 'B'
m = re.search("a.b", "A\nBC", flags=re.IGNORECASE)
m is None
# Out: True
m = re.search("a.b", "A\nBC", flags=re.IGNORECASE|re.DOTALL)
m.group()
# Out: 'A\nB'
共通のフラグ
旗 | 簡単な説明 |
---|---|
re.IGNORECASE 、 re.I | 大文字小文字の区別を無視する |
re.DOTALL 、 re.S | 作る. 改行を含むすべてにマッチする |
re.MULTILINE 、 re.M | MAKES ^ 一致ラインの始まりと$ 行の終わり |
re.DEBUG | デバッグ情報を有効にする |
使用可能なすべてのフラグの完全なリストについては、 ドキュメントをチェックしてください
インラインフラグ
ドキュメントから:
(?iLmsux)
(セット 'i'、 'L'、 'm'、 's'、 'u'、 'x'からの1つ以上の文字)グループは空の文字列と一致します。 re.I(大文字小文字無視)、re.L(ロケール依存)、re.M(複数行)、re.S(ドット一致)、re.U(Unicode依存)、および対応するフラグを設定します。正規表現全体のre.X(冗長)。これは、フラグ引数をre.compile()関数に渡すのではなく、正規表現の一部としてフラグをインクルードする場合に便利です。
(?x)フラグは、式がどのように解析されるかを変更することに注意してください。これは、最初に式文字列で使用するか、1つ以上の空白文字の後に使用する必要があります。フラグの前に空白以外の文字がある場合、結果は未定義です。
`re.finditer`を使ってマッチを反復する
re.finditer
を使用すると、文字列内のすべての一致を反復処理できます。これにより、文字列(インデックス)内の一致する場所に関する情報など、追加の情報をre.findall
する場合と比較して、次のようになります。
import re
text = 'You can try to find an ant in this string'
pattern = 'an?\w' # find 'an' either with or without a following word character
for match in re.finditer(pattern, text):
# Start index of match (integer)
sStart = match.start()
# Final index of match (integer)
sEnd = match.end()
# Complete match (string)
sGroup = match.group()
# Print match
print('Match "{}" found at: [{},{}]'.format(sGroup, sStart,sEnd))
結果:
Match "an" found at: [5,7]
Match "an" found at: [20,22]
Match "ant" found at: [23,26]
特定の場所でのみ式を一致させる
特定の場所でのみ式をマッチさせたい場合があります。次の文を考えてみましょう。
An apple a day keeps the doctor away (I eat an apple everyday).
ここでは、 "リンゴ"が2回発生します。これは、新しいregex
モジュールでサポートされているいわゆるバックトラッキング制御動詞で解決できます。アイデアは:
forget_this | or this | and this as well | (but keep this)
Appleの例では、これは次のようになります。
import regex as re
string = "An apple a day keeps the doctor away (I eat an apple everyday)."
rx = re.compile(r'''
\([^()]*\) (*SKIP)(*FAIL) # match anything in parentheses and "throw it away"
| # or
apple # match an apple
''', re.VERBOSE)
apples = rx.findall(string)
print(apples)
# only one
これは括弧の外側にある場合にのみ "apple"にマッチします。
それはどのように動作するのです:
- 左から見ると、正規表現エンジンはすべてを左に消費し、
(*SKIP)
は「常に真のアサーション」として機能します。その後、正しく失敗し(*FAIL)
、バックトラックします。 - 今すぐ右から左へ
(*SKIP)
ポイントに戻ります(別名、バックトラック中)。左に行くことは禁じられています。代わりに、エンジンは左に何も捨てて、(*SKIP)
が呼び出されたポイントにジャンプするように指示されます。