Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonの正規表現を使ったパターンマッチング入門


正規表現とは?

実際のプログラミングの世界では、文字列の解析処理はほとんどの場合、正規表現によって行われています。Pythonにおける正規表現とは、テキストのパターンを照合(マッチング)するための手法です。

Pythonには標準で「re」モジュールが付属しており、これによって正規表現の機能が提供されます。追加のインストールは不要です。

Pythonでの正規表現検索は、一般的に次のように記述します。

match = re.search(pattern, string)

re.search()メソッドは、「正規表現パターン」と「検索対象の文字列」の2つの引数を受け取り、その文字列の中からパターンを探します。パターンが見つかればマッチオブジェクトを返し、見つからなければNoneを返します。つまり正規表現とは、与えられた文字列が特定のパターンに一致するかどうかを判定し、必要に応じて関連情報を含む部分文字列を抽出するための仕組みです。

正規表現を使うと、次のような疑問に答えることができます。

  • この文字列は有効なURLか?

  • /etc/passwdの中で、特定のグループに属するユーザーはどれか?

  • ログファイル内のすべての警告メッセージの日時はいつか?

  • 訪問者が入力したURLから、ユーザー名と要求されたドキュメントは何か?

パターンのマッチング

正規表現は、複雑なミニ言語のようなものです。特殊な文字を使って未知の文字列と照合しますが、まずは英字・数字・スペースなど、常に自分自身と一致するリテラル文字から始めてみましょう。基本的な例を見てみます。

# 正規表現には 're' モジュールが必要
import re
#
search_string = "TutorialsPoint"
pattern = "Tutorials"
match = re.match(pattern, search_string)
# search() の後のif文で成功したかどうかを判定
if match:
    print("regex matches: ", match.group())
else:
    print('pattern not found')

実行結果

regex matches: Tutorials

文字列のマッチング

Pythonの「re」モジュールには多数のメソッドが用意されており、特定の正規表現が指定した文字列に一致するかどうかを調べるには re.search() を使います。また、re.MatchObject は、文字列のどの部分でマッチが見つかったかといった追加情報も提供してくれます。

構文

matchObject = re.search(pattern, input_string, flags=0)

# 正規表現には 're' モジュールが必要
import re
# 日付文字列にマッチする正規表現を使用
regex = r"([a-zA-Z]+) (\d+)"
if re.search(regex, "Jan 2"):
    match = re.search(regex, "Jan 2")
    # 文字列の先頭と末尾でマッチするため [0, 5) が出力される
    print("Match at index %s, %s" % (match.start(), match.end()))
    # groups にはマッチした値が格納される。具体的には:
    # match.group(0) は常にマッチした文字列全体を返す
    # match.group(1), match.group(2), ... は入力文字列の左から順に
    # キャプチャグループを返す
    # match.group() は match.group(0) と同等
    # したがって "Jan 2" が出力される
    print("Full match: %s" % (match.group(0)))
    # したがって "Jan" が出力される
    print("Month: %s" % (match.group(1)))
    # したがって "2" が出力される
    print("Day: %s" % (match.group(2)))
else:
    # re.search() がマッチしなければ None が返る
    print("Pattern not Found! ")

実行結果

Match at index 0, 5
Full match: Jan 2
Month: Jan
Day: 2

上記のメソッドは最初のマッチが見つかった時点で処理を終了するため、データの大量抽出よりも、正規表現の動作確認やテストに向いています。

キャプチャグループ

パターンに括弧 () が2つ以上含まれている場合、findall() とグループ化の仕組みを組み合わせることで、結果は文字列のリストではなくタプルとして返されます。各マッチは1つのタプルで表され、それぞれのタプルには group(1)、group(2)… のデータが含まれます。

import re
regex = r'([\w\.-]+)@([\w\.-]+)'
str = ('hello john@hotmail.com, hello@Tutorialspoint.com, hello python@gmail.com')
matches = re.findall(regex, str)
print(matches)
for tuple in matches:
    print("Username: ",tuple[0]) # ユーザー名
    print("Host: ",tuple[1]) # ホスト名

実行結果

[('john', 'hotmail.com'), ('hello', 'Tutorialspoint.com'), ('python', 'gmail.com')]
Username: john
Host: hotmail.com
Username: hello
Host: Tutorialspoint.com
Username: python
Host: gmail.com

文字列の検索と置換

もうひとつのよくあるタスクは、指定した文字列内のパターンに一致するすべての箇所を検索して置き換えることです。re.sub(pattern, replacement, string) はまさにそれを行います。たとえば、古いメールドメインをすべて新しいドメインに置き換える例を見てみましょう。

コード

# 必要なライブラリ
import re
# 対象の文字列
str = ('hello john@hotmail.com, hello@Tutorialspoint.com, hello python@gmail.com, Hello World!')
# マッチさせるパターン
pattern = r'([\w\.-]+)@([\w\.-]+)'
# マッチしたパターンを次の文字列で置換
replace = r'\1@XYZ.com'
    ## re.sub(pat, replacement, str) -- 置換済みの新しい文字列を返す
    ## \1 は group(1)、\2 は group(2) に対応
print (re.sub(pattern, replace, str))

実行結果

hello john@XYZ.com, hello@XYZ.com, hello python@XYZ.com, Hello World!

正規表現のオプションフラグ

上記のようなPythonの正規表現では、さまざまなオプションを使ってパターンマッチの動作を変更できます。これらのオプション引数(フラグ)は、search() や findall() などの関数に追加して指定します。たとえば re.search(pattern, string, re.IGNORECASE) のように使います。

  • IGNORECASE

    名前の通り、パターンの大文字・小文字を区別しなくなります。このフラグを使うと、「a」と「A」のどちらを含む文字列でもマッチします。

  • DOTALL

    re.DOTALL を指定すると、メタ文字のドット(.)が改行文字(\n)を含むすべての文字にマッチするようになります。

  • MULTILINE

    re.MULTILINE を指定すると、文字列の各行の先頭(^)と末尾($)に対してマッチできるようになります。通常、^ と $ は文字列全体の先頭と末尾にしかマッチしませんが、このフラグにより行単位のマッチが可能になります。


  1. Pythonでパターンを出力する方法|三角形・数字・アルファベット・ピラミッドのコード例

    Pythonでパターンを出力するには、ネストされた(入れ子構造の)forループを使用します。外側のループで行数を制御し、内側のループで列数を処理します。そしてprint文を工夫することで、目的に応じたさまざまなパターンを作成できます。パターンには、星(アスタリスク)パターン、数字パターン、アルファベットパターンなどがあり、三角形やピラミッドなど、さまざまな形状にも対応できます。パターン出力の基本これらのパターンは、print文を少し変更しながらforループを組み合わせることで出力できます。基本的な考え方はどのパターンも共通しており、違いはごくわずかです。ここからは、代表的なパターンのコードを実

  2. Pythonで描く葉序(ようじょ)パターン ― フィボナッチ螺旋の美しさをコードで再現

    葉序パターンとは? 植物学の授業や植物の世界でよく耳にする「葉序(ようじょ)」とは、植物の茎に花・葉・種子などがどのような順序で配置されるかを表す用語です。この配置は、いわゆる「フィボナッチ螺旋」と非常によく似たパターンを示します。 フィボナッチ螺旋は、パスカルの三角形にも似た規則性を持つ数列、すなわちフィボナッチ数列に基づいています。フィボナッチ数列は次のように続きます。 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 … この数列の特徴は、各項が直前の2つの数の和になっているという点です。自然界のあらゆる場所に潜む、シンプルながら奥深い数理構造と言えま