Python - 正規表現

こんにちは、将来のPythonの魔法使いたち!今日、私たちはPythonの正規表現(regex)の世界に冒険する興奮な旅に出かけます。regexを聞いたことがないという方も心配しないでください。このチュートリアルの終わりまでに、この強力なツールをプロのように使えるようになるでしょう!

Python - Reg Expressions

正規表現とは?

飛び込む前に、正規表現とは何かを理解しましょう。あなたがテキストの海の中から特定のパターンを見つける探偵だと想像してみてください。正規表現はあなたの虫眼鏡のように、パターンに基づいて文字列を検索したり操作したりするのを助けます。クールでしょう?

ラップ文字列

Pythonでregexを使うとき、私たちはしばしばラップ文字列を使います。これらは「r」で始まり、バックスラッシュをリテラル文字として扱います。これはregexでは非常に便利ですなぜならバックスラッシュは一般的です。

# 普通の文字列
print("Hello\nWorld")
# ラップ文字列
print(r"Hello\nWorld")

最初の場合、あなたは「Hello」と「World」が別の行に表示されます。二つ目の場合、あなたは「Hello\nWorld」として表示されます。これはregexのパターンで重要です。

メタ文字

メタ文字はregexの構成ブロックです。これらは特別な意味を持ち、パターンを定義するのに役立ちます。一般的なものをいくつか見てみましょう:

メタ文字 意味
. 改行文字以外の任意の文字
^ 文字列の開始
$ 文字列の終了
* 0回以上の繰り返し
+ 1回以上の繰り返し
? 0回または1回の繰り返し
{} 明示的に指定された回数の繰り返し
[] マッチする文字のセットを指定
\ 特別文字をエスケープ

re.match() 関数

re.match()関数は文字列の先頭にパターンが一致するか試みます。一致する場合はマッチオブジェクトを返し、それ以外の場合はNoneを返します。

import re

result = re.match(r"Hello", "Hello, World!")
if result:
print("マッチが見つかりました:", result.group())
else:
print("マッチが見つかりません")

これは "マッチが見つかりました: Hello" を印刷します。group()メソッドは一致した部分文字列を返します。

re.search() 関数

re.match()は文字列の先頭に一致するか探しますが、re.search()は文字列全体をスキャンして一致するか探します。

import re

result = re.search(r"World", "Hello, World!")
if result:
print("マッチが見つかりました:", result.group())
else:
print("マッチが見つかりません")

これは "マッチが見つかりました: World" を印刷します。

マッチ対スキャン

match()search()の主な違いは、match()は文字列の先頭にのみ一致を確認するのに対して、search()は文字列のどこに一致するかを確認することです。

re.findall() 関数

re.findall()関数は文字列中のパターンのすべての非重複の一致をリストとして返します。

import re

text = "The rain in Spain falls mainly in the plain"
result = re.findall(r"ain", text)
print(result)

これは ['ain', 'ain', 'ain'] を印刷します。

re.sub() 関数

re.sub()関数は文字列中のパターンのすべての出現を置換文字列に置き換えます。

import re

text = "The rain in Spain"
result = re.sub(r"a", "o", text)
print(result)

これは "The roin in Spoin" を印刷します。

re.compile() 関数

re.compile()関数は再利用のためのregexオブジェクトを作成し、同じパターンを複数回使用する場合はより効率的です。

import re

pattern = re.compile(r"\d+")
result1 = pattern.findall("There are 123 apples and 456 oranges")
result2 = pattern.findall("I have 789 bananas")

print(result1)
print(result2)

これは ['123', '456']['789'] を印刷します。

re.finditer() 関数

re.finditer()関数は文字列中のパターンのすべての非重複の一致を返すイテレータを返します。

import re

text = "The rain in Spain"
for match in re.finditer(r"ain", text):
print(f"'{match.group()}'が位置 {match.start()}-{match.end()} で見つかりました")

これは以下を印刷します:

'ain'が位置 5-8 で見つかりました
'ain'が位置 17-20 で見つかりました

Python Regexの使用例

正規表現には多くの実践的な応用があります。一般的な使用例を見てみましょう:

かなで始まる単語を見つける

import re

text = "An apple a day keeps the doctor away"
vowel_words = re.findall(r'\b[aeiouAEIOU]\w+', text)
print(vowel_words)

これは ['An', 'apple', 'a', 'away'] を印刷します。

正規表現修飾子:オプションフラグ

Pythonのreモジュールは、パターンの解釈方法を変更するためのいくつかのオプションフラグを提供します:

フラグ 説明
re.IGNORECASE (re.I) 大文字小文字を区別しない一致
re.MULTILINE (re.M) ^が各行の先頭、$が各行の末尾に一致
re.DOTALL (re.S) .が改行文字を含む任意の文字に一致
re.VERBOSE (re.X) 読みやすいregexパターンを書くことができる

正規表現パターン

さらに高度なパターンを探検しましょう:

文字クラス

文字クラスはマッチする文字のセットを指定できます:

import re

text = "The quick brown fox jumps over the lazy dog"
result = re.findall(r"[aeiou]", text)
print(result)

これはテキスト中のすべての母音を印刷します。

特殊文字クラス

Pythonのregexは特殊文字クラスをサポートしています:

クラス 説明
\d 任意の10進数数字
\D 数字以外の任意の文字
\s 任意の空白文字
\S 空白文字以外の任意の文字
\w 任意のアルファベット数字文字
\W アルファベット数字文字以外の任意の文字

繰り返しの例

パターンが何回出現するかを指定できます:

import re

text = "I have 111 apples and 22 oranges"
result = re.findall(r"\d{2,3}", text)
print(result)

これは ['111', '22'] を印刷し、2または3桁の数字をマッチします。

非貪欲な繰り返し

デフォルトでは、繰り返しは貪欲で、できるだけ多くの文字をマッチします。繰り返しの後ろに?を追加すると非貪欲になります:

import re

text = "<h1>Title</h1><p>Paragraph</p>"
greedy = re.findall(r"<.*>", text)
non_greedy = re.findall(r"<.*?>", text)
print("Greedy:", greedy)
print("Non-greedy:", non_greedy)

これは貪欲と非貪欲のマッチの違いを示します。

括弧でのグループ化

括弧を使うとパターンの一部をグループ化できます:

import re

text = "John Smith ([email protected])"
result = re.search(r"(\w+) (\w+) \((\w+@\w+\.\w+)\)", text)
if result:
print(f"フルネーム: {result.group(1)} {result.group(2)}")
print(f"メール: {result.group(3)}")

これはテキストから名前とメールを抽出します。

バックリファレンス

バックリファレンスは前に一致したグループを参照できます:

import re

text = "<h1>Title</h1><p>Paragraph</p>"
result = re.findall(r"<(\w+)>.*?</\1>", text)
print(result)

これは開始タグと終了タグが一致するHTMLタグをマッチします。

代替

|文字が代替を指定します:

import re

text = "The color of the sky is blue or gray"
result = re.search(r"blue|gray", text)
if result:
print(f"見つかった色: {result.group()}")

これは "blue" または "gray" に一致します。

アンカー

アンカーはテキストの位置を指定します:

import re

text = "Python is awesome"
start = re.match(r"^Python", text)
end = re.search(r"awesome$", text)
print(f"Pythonで始まる: {bool(start)}")
print(f"awesomeで終わる: {bool(end)}")

これはテキストが "Python" で始まり "awesome" で終わるかどうかを確認します。

括弧の特殊構文

括弧はグループ化以外にも使えます:

  • (?:...) は非キャプチャグループを作成
  • (?P...) は名前付きグループを作成
  • (?=...) はポジティブルックアヘッドを作成
  • (?!...) はネガティブルックアヘッドを作成
import re

text = "Python version 3.9.5"
result = re.search(r"Python (?:version )?(?P<version>\d+\.\d+\.\d+)", text)
if result:
print(f"バージョン: {result.group('version')}")

これは "version" が存在するかどうかに関わらず、バージョン番号を抽出します。

それで、これで終わりです、皆さん!私たちはPythonのregexの世界を旅し、基本的なものから非常に高度な概念までを探検しました。覚えておいてください、強力なツールとして、regexは実践していないとマスターにはなりません。最初は難しいと感じるかもしれませんが、続けて実験し、すぐにはプロの探偵のようにパターンを見つけることができるようになります!コーディングを楽しんでください!

Credits: Image by storyset