【保存版】Pythonの正規表現をコード付きで徹底解説|初心者向け

※本サイトにはプロモーション・広告が含まれています。

(最終更新月:2023年6月)

✔このような方へ向けて書かれた記事となります

「Pythonで正規表現ってどのように扱うのだろうか?」

「Python正規表現の使い方が知りたい」

「Python正規表現の実例が見たい」

✔当記事を通じてお伝えすること

  • Python正規表現の基本概念
  • Python正規表現の書き方やそのアプローチ
  • Python正規表現の実例・事例

当記事では、Python正規表現の基本から応用まで、具体的なケーススタディを用いながら、詳細に解説しています。

是非最後までご覧ください。

筆者プロフィール

筆者プロフィールアイコン

【現職】プロダクトマネージャー

【副業】ブログ(月間17万PV)/YouTube/Web・アプリ制作

「プログラミング × ライティング × 営業」の経験を活かし、30後半からのIT系職へシフト。当サイトでは、実際に手を動かせるWebアプリの開発を通じて、プログラミングはもちろん、IT職に必要な情報を提供していきます。

【当ブログで紹介しているサイト】

当サイトチュートリアルで作成したデモ版日報アプリ

Django × Reactで開発したツール系Webアプリ

✔人に見せても恥ずかしくないコードを書こう

「リーダブルコード」は、わかりやすく良いコードの定義を教えてくれる本です。

  • 見るからにきれいなコードの書き方
  • コードの分割方法
  • 変数や関数の命名規則

エンジニアのスタンダートとすべき基準を一から解説しています。

何回も読むのに値する本なので、ぜひ手にとって読んでみてください。

正規表現の基本

こちらでは、正規表現の基本についてお伝えします。

  • 正規表現とは?
  • 正規表現の基本パターン
  • 正規表現の参照リスト
  • Pythonでの正規表現

正規表現とは?

正規表現は、文字列のパターンを表現するための記法です。

この記法を使用して、特定のパターンに一致する文字列を検索、置換、抽出できます。

例えば、電話番号やメールアドレスなどの構造を持った文字列を見つける場合に正規表現が非常に有用です。

import re

# 電話番号のパターンを定義する正規表現
pattern = r"\d{3}-\d{4}-\d{4}|\d{4}-\d{3}-\d{4}"

# 検索対象のテキスト
text = "私の電話番号は080-1234-5678です。お問い合わせは0120-345-6789までお願いします。"

# 正規表現で電話番号を検索する
matches = re.findall(pattern, text)

# 検索結果を表示する
if matches:
    for match in matches:
        print("電話番号:", match)
else:
    print("電話番号は見つかりませんでした。")

正規表現の基本パターン

正規表現には多くの基本パターンがあります。

  • 「.」:任意の1文字
  • 「\d」:任意の数字
  • 「\w」:単語の一部

これらを組み合わせることで、さまざまな文字列パターンを表現することができます。

import re

# 正規表現パターン
pattern = r"\w{3}\d{2}\."

# 検索対象のテキスト
text = "abc12.txt, xyz34.jpg, pqr56.doc"

# 正規表現でパターンに一致する文字列を検索する
matches = re.findall(pattern, text)

# 検索結果を表示する
if matches:
    for match in matches:
        print("マッチした文字列:", match)
else:
    print("一致する文字列は見つかりませんでした。")

正規表現の参照リスト

正規表現のパターンは非常に多く、一度に覚えるのは大変です。

そのため、手元に正規表現のチートシートやリファレンスを置いておくと便利です。

パターン意味例 -> マッチする文字列
.任意の1文字“a.b” -> “aab”, “a1b”
\w英数字またはアンダースコア“\w+” -> “abc123_”, “word”
\d任意の数字“\d{3}” -> “123”, “987”
\s空白文字“hello\sworld” -> “hello world”
\b単語の境界r”\bcat\b” -> “cat”, “catnip”
^行の先頭“^hello” -> “hello, world!”, “hello”
$行の末尾“world!$” -> “Hello, world!”, “Goodbye, world!”
*直前のパターンの0回以上の繰り返し“ab*c” -> “ac”, “abbbc”
+直前のパターンの1回以上の繰り返し“ab+c” -> “abc”, “abbbbbc”
?直前のパターンの0回または1回の繰り返し“colou?r” -> “color”, “colour”
{n}直前のパターンのn回の繰り返し“a{3}” -> “aaa”, “aa”
{n,}直前のパターンのn回以上の繰り返し“a{2,}” -> “aa”, “aaa”
{n,m}直前のパターンのn回以上m回以下の繰り返し“a{2,4}” -> “aa”, “aaa”, “aaaa”
[…]文字クラス“[aeiou]” -> “apple”, “banana”
[^…]否定文字クラス“[^0-9]” -> “abc”, “XYZ”
(…)グループ“(abc)+” -> “abc”, “abcabc”
|OR演算子“apple|orange” -> “apple”, “orange”
(?i)大文字と小文字を区別しない“(?i)apple” -> “Apple”, “aPpLe”
(?m)複数行モード“^fruit” -> “fruit”, “juicy fruit”
(?s)ドットが改行を含むすべての文字にマッチする“(?s).+” -> “This\nis\nmultiline”
(?x)

また正規表現のテスターを利用して、実際に試しながら正規表現を学びましょう。

以下などを参考にしてください。

regex101: build, test, and debug regex
Regular expression tester with syntax highlighting, explanation, cheat sheet for PHP/PCRE, Python, GO, JavaScript, Java,...

Pythonでの正規表現

Pythonではreモジュールを使って正規表現を扱います。

このモジュールをインポートすることで、正規表現を使用して文字列の検索、置換、分割などを行うことができます。

import re

Pythonのreモジュール

こちらでは、Pythonのreモジュールについてお伝えします。

  • reモジュールのインポート
  • 主要な関数と使い方
  • Flagsと例外処理

reモジュールのインポート

Pythonで正規表現を利用するには、まずreモジュールをインポートしてください。

これはimport reというコードをプログラムの先頭に記述することでおこなえます。

import re

主要な関数と使い方

reモジュールには、さまざまな関数が提供されています。

  • re.match():文字列の先頭が正規表現にマッチするかをチェック
  • re.search()は文字列全体でマッチする部分を探す
  • re.findall():正規表現にマッチする部分をすべてリストで返す

以下がサンプルコードです。

import re

# 文字列の先頭が正規表現にマッチするかをチェックする
pattern = r"hello"
text = "hello world"
match = re.match(pattern, text)
if match:
    print("Match found:", match.group())
else:
    print("No match")

# 文字列全体でマッチする部分を探す
pattern = r"world"
text = "hello world"
match = re.search(pattern, text)
if match:
    print("Match found:", match.group())
else:
    print("No match")

# 正規表現にマッチする部分をすべてリストで返す
pattern = r"\d+"
text = "I have 123 apples and 456 bananas"
matches = re.findall(pattern, text)
if matches:
    for match in matches:
        print("Match found:", match)
else:
    print("No matches")

Flagsと例外処理

reモジュールでは、正規表現の動作を制御するフラグを設定できます。

例えば、re.IGNORECASEフラグは、大文字小文字を区別せずにマッチングをおこなえるもの。

また、正規表現のパターンが不正な場合など、例外処理を行うことが重要です。

import re

# 大文字小文字を区別せずにマッチングする
pattern = r"apple"
text = "I have an Apple"
match = re.search(pattern, text, re.IGNORECASE)
if match:
    print("Match found:", match.group())
else:
    print("No match")

# 正規表現のパターンが不正な場合の例外処理
try:
    pattern = r"(?i"
    text = "Hello world"
    match = re.search(pattern, text)
    if match:
        print("Match found:", match.group())
    else:
        print("No match")
except re.error as e:
    print("Error:", e)

正規表現の詳細なシンタックス

こちらでは、正規表現の詳細なシンタックスについてお伝えします。

  • 文字のマッチング
  • 数字のマッチング
  • 量指定子と繰り返しマッチング
  • 貪欲マッチ(.)と非貪欲マッチ(.?)

文字のマッチング

正規表現では、特定の文字に一致するパターンを作成できます。

たとえば、[a-z]は小文字のアルファベットにマッチし、[A-Z]は大文字のアルファベットにマッチします。

また、.(ドット)は任意の1文字にマッチします。

import re

# 小文字のアルファベットにマッチ
pattern = r"[a-z]"
text = "Hello World"
matches = re.findall(pattern, text)
print("Matches:", matches)

# 大文字のアルファベットにマッチ
pattern = r"[A-Z]"
text = "Hello World"
matches = re.findall(pattern, text)
print("Matches:", matches)

# 任意の1文字にマッチ
pattern = r"."
text = "Hello World"
matches = re.findall(pattern, text)
print("Matches:", matches)

#出力結果
# Matches: ['e', 'l', 'l', 'o', 'o', 'r', 'l', 'd']
# Matches: ['H', 'W']
# Matches: ['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']

数字のマッチング

数字にマッチするためのパターンも作成できます。

\d:任意の数字にマッチ

[0-9]:うえと同様の目的で使用

{n}:指定した回数だけ繰り返される数字にマッチ

import re

# 任意の数字にマッチ
pattern = r"\d"
text = "abc 123 def"
matches = re.findall(pattern, text)
print("Matches:", matches)

# [0-9]と同様に数字にマッチ
pattern = r"[0-9]"
text = "abc 123 def"
matches = re.findall(pattern, text)
print("Matches:", matches)

# 3桁の数字にマッチ
pattern = r"\d{3}"
text = "abc 123 def 4567 ghi"
matches = re.findall(pattern, text)
print("Matches:", matches)

量指定子と繰り返しマッチング

正規表現の量指定子を利用して、パターンの繰り返し回数を指定できます。

  • *:0回以上の繰り返し
  • +:1回以上の繰り返し
  • ?:0回または1回の繰り返し

以下がその例です。

import re

# *を使用して0回以上の繰り返しにマッチ
pattern = r"ab*c"
texts = ["ac", "abc", "abbc", "abbbbc"]
for text in texts:
    if re.match(pattern, text):
        print(f"Matched: {text}")

# +を使用して1回以上の繰り返しにマッチ
pattern = r"ab+c"
texts = ["ac", "abc", "abbc", "abbbbc"]
for text in texts:
    if re.match(pattern, text):
        print(f"Matched: {text}")

# ?を使用して0回または1回の繰り返しにマッチ
pattern = r"ab?c"
texts = ["ac", "abc", "abbc", "abbbbc"]
for text in texts:
    if re.match(pattern, text):
        print(f"Matched: {text}")

# 出力結果
# Matched: ac
# Matched: abc
# Matched: abbc
# Matched: abbc
# Matched: abbc
# Matched: abbc

貪欲マッチ(.)と非貪欲マッチ(.?)

正規表現でマッチングさせる方法として、以下の2つがあります。

  • 可能な限り多くの文字にマッチしようとする貪欲マッチ
  • 最小限の文字にマッチする非貪欲マッチ

.*は貪欲マッチで、.*?は非貪欲マッチです。

import re

# 貪欲マッチの例
pattern = r"a.*b"
text = "aabab"
match = re.search(pattern, text)
if match:
    print("Greedy match:", match.group())

# 非貪欲マッチの例
pattern = r"a.*?b"
text = "aabab"
match = re.search(pattern, text)
if match:
    print("Non-greedy match:", match.group())

# 出力結果
# Greedy match: aabab
# Non-greedy match: aab

文字列検索の方法

こちらでは、Pythonで正規表現を使用して文字列を検索する方法についてお伝えします。

  • re.search()
  • re.findall()
  • re.match()とsearch()の違い

re.search()

re.search()は、文字列内で正規表現にマッチする部分を検索するメソッドです。

マッチした最初の位置を返します。

import re

pattern = r"abc"
text = "abcdef"

match = re.search(pattern, text)
if match:
    print("マッチが見つかりました。位置:", match.start())
else:
    print("マッチが見つかりませんでした。")

# 出力結果
# マッチが見つかりました。位置: 0

re.findall()

re.findall()は、正規表現にマッチするすべての部分を文字列から見つけてリストとして返します。

文字列内のマッチする部分が複数ある場合に便利です。

import re

pattern = r"\d+"
text = "今日の天気は25度で、明日は30度になる予定です。"

matches = re.findall(pattern, text)
if matches:
    print("マッチが見つかりました:", matches)
else:
    print("マッチが見つかりませんでした。")

# 出力結果
# マッチが見つかりました: ['25', '30']

re.match()とsearch()の違い

re.match()とsearch()の違いは以下のとおり。

  • re.match():文字列の先頭が正規表現にマッチするかを確認
  • re.search()は文字列全体でマッチする部分を探す

文字列の先頭以外にマッチする部分がある場合、re.match()は何も返しません。

対してre.search()は、マッチする部分を見つけるのです。

import re

pattern = r"hello"
text = "hello world"

# re.match()を使用して文字列の先頭が正規表現にマッチするかを確認
match_result = re.match(pattern, text)
if match_result:
    print("re.match(): マッチしました")
else:
    print("re.match(): マッチしませんでした")

# re.search()を使用して文字列全体でマッチする部分を探す
search_result = re.search(pattern, text)
if search_result:
    print("re.search(): マッチしました")
else:
    print("re.search(): マッチしませんでした")

# 出力結果
# re.match(): マッチしませんでした
# re.search(): マッチしました

文字列の置換と書き換え

こちらでは、Pythonの正規表現を使用して文字列を置換・書き換える方法についてお伝えします。

  • re.sub()の使い方
  • 文字列置換の応用例

re.sub()の使い方

re.sub()関数を使用して、正規表現にマッチする部分を別の文字列に置換できます。

引数には以下を指定します。

  • 第一引数に正規表現パターン
  • 第二引数に置換する文字列
  • 第三引数に対象の文字列
import re

pattern = r'\d'
replacement = '*'
text = 'abc123'

result = re.sub(pattern, replacement, text)
print(result)

# 出力結果
# abc***

文字列置換の応用例

文字列置換は、テキストデータのクリーニングやフォーマットの整形に広く使用されます。

たとえば、日付のフォーマットを統一したり、機密情報をマスクしたりする場合などです。

import re

text = "私の電話番号は080-1234-5678です。お問い合わせは012-345-6789までお願いします。"

# 電話番号をマスクする
masked_text = re.sub(r'\d{3}-\d{4}-\d{4}', '***-****-****', text)

print(masked_text)

# 出力結果
# 私の電話番号は***-****-****です。お問い合わせは***-****-****までお願いします。

グループ化とキャプチャ

こちらでは、正規表現でのグループ化とキャプチャについてお伝えします。

  • グループ化の方法
  • キャプチャしたマッチング結果の活用
  • group()でターゲット文字の取得

グループ化の方法

正規表現内で括弧()を使用することで、部分的なマッチングをグループ化できます。

これは、マッチした文字列の一部を別々に扱いたい場合などに有用です。

import re

text = "John Doe: 25 years old, Jane Smith: 30 years old"

# 名前と年齢の情報を抽出する正規表現パターン
pattern = r"(\w+\s\w+):\s(\d+)\syears old"

# 正規表現でグループ化して情報を抽出する
matches = re.findall(pattern, text)

# 抽出した情報を表示する
for match in matches:
    name = match[0]
    age = match[1]
    print("Name:", name)
    print("Age:", age)
    print()

# 出力結果
# Name: John Doe
# Age: 25

# Name: Jane Smith
# Age: 30

キャプチャしたマッチング結果の活用

グループ化を利用してキャプチャした結果は、後処理や置換に使用できます。

正規表現で電話番号の各部分を別々にキャプチャして、異なるフォーマットで表示してみましょう。

import re

phone_numbers = [
    "080-1234-5678",
    "0120-987-6543",
    "090-111-2222"
]

pattern = r"(\d{3})-(\d{4})-(\d{4})"

for phone_number in phone_numbers:
    match = re.match(pattern, phone_number)
    if match:
        area_code = match.group(1)
        local_code = match.group(2)
        subscriber_number = match.group(3)
        
        print("Original: ", phone_number)
        print("Formatted: ({}) {}-{}".format(area_code, local_code, subscriber_number))
        print()

以下が出力結果です。

Original:  080-1234-5678
Formatted: (080) 1234-5678

Original:  0120-987-6543
Formatted: (0120) 987-6543

Original:  090-111-2222
Formatted: (090) 111-2222

group()でターゲット文字の取得

group()メソッドを使用すると、正規表現でキャプチャしたグループの内容を取得できます。

group(0)はマッチした全体を返し、group(1)group(2)、… はそれぞれのグループにマッチした部分を返す役割です。

import re

text = "Today is 2022-06-30"

pattern = r"(\d{4})-(\d{2})-(\d{2})"

match = re.search(pattern, text)
if match:
    print("Full Match:", match.group(0))
    print("Year:", match.group(1))
    print("Month:", match.group(2))
    print("Day:", match.group(3))

# 出力結果
# Full Match: 2022-06-30
# Year: 2022
# Month: 06
# Day: 30

改行とRaw文字列記法

こちらでは、正規表現での改行の扱いと、PythonでのRaw文字列記法についてお伝えします。

  • 正規表現での改行の扱い
  • Raw文字列記法の活用

正規表現での改行の扱い

正規表現では、通常、.(ドット)は改行を除く任意の文字にマッチします。

しかし、re.DOTALLフラグを使用すると、.は改行にもマッチさせられるのです。

\nを使って、改行に直接マッチさせられることも覚えておきましょう。

import re

text = "Hello\nWorld"

pattern1 = r".+"
pattern2 = r".+"
pattern3 = r"\n"

match1 = re.search(pattern1, text)
if match1:
    print("Match 1:", match1.group())

match2 = re.search(pattern2, text, re.DOTALL)
if match2:
    print("Match 2:", match2.group())

match3 = re.search(pattern3, text)
if match3:
    print("Match 3:", match3.group())

出力結果

Match 1: Hello
Match 2: Hello
World
Match 3: 

Raw文字列記法の活用

Raw文字列を活用すると、コードが短く、明確になります。

なぜならRaw文字列(r”)を使用すると、バックスラッシュをエスケープせずに書けるからです。

通常は、バックスラッシュをエスケープ文字として扱うため、正規表現中でバックスラッシュを使用する際には二重にする必要があります。

以下がその比較例です。

import re

# Raw文字列を使用する場合
pattern1 = r'\d+'  # バックスラッシュをエスケープせずに直接記述

# 通常の文字列を使用する場合
pattern2 = '\\d+'  # バックスラッシュをエスケープするために二重に記述

text = '1234'

match1 = re.search(pattern1, text)
if match1:
    print("Match 1:", match1.group())

match2 = re.search(pattern2, text)
if match2:
    print("Match 2:", match2.group())

# 出力結果
# Match 1: 1234
# Match 2: 1234

Pythonと正規表現を活用した実践例

こちらでは、Pythonと正規表現を活用した具体的な実践例についてお伝えします。

  • ペアの確認
  • 電話帳作成
  • テキストの秘匿
  • 副詞の検索

ペアの確認

Pythonの正規表現を使って、テキスト内の括弧が正しくペアになっているかを確認できます。

これは、プログラムのコードや数式のエラーチェックに役立つものです。

import re

def check_parentheses(text):
    pattern = r'\([^()]*\)'  # 括弧で囲まれた部分を抽出するパターン

    matches = re.findall(pattern, text)  # パターンにマッチするすべての部分を抽出
    for match in matches:
        if len(match) % 2 != 0:
            return False  # 括弧の数が奇数なら不正なペアと判断
    return True

# テキストをチェック
text1 = "This is a (valid) example."  # 括弧が正しくペアになっている
print(check_parentheses(text1))  # True

text2 = "This is an (invalid example."  # 括弧が閉じられていない
print(check_parentheses(text2))  # False

text3 = "This is an )invalid( example."  # 閉じ括弧が開き括弧よりも先に現れている
print(check_parentheses(text3))  # False

電話帳作成

電話番号のリストから、正規表現を使って各番号の形式を整え、電話帳を作成できます。

import re

def format_phone_numbers(phone_numbers):
    formatted_numbers = []
    pattern = r'(\d{3})-(\d{4})-(\d{4})'  # 電話番号の正規表現パターン

    for number in phone_numbers:
        # 電話番号を整形する
        match = re.match(pattern, number)
        if match:
            formatted_number = match.group(1) + '-' + match.group(2) + '-' + match.group(3)
            formatted_numbers.append(formatted_number)

    return formatted_numbers

# 電話番号のリスト
phone_numbers = [
    '080-1234-5678',
    '090-1234-5678',
    '070-1234-5678',
    '0120-123-4567',
    '03-1234-5678',
]

# 電話番号を整形して電話帳を作成
formatted_phone_book = format_phone_numbers(phone_numbers)

# 整形された電話番号のリストを表示
for number in formatted_phone_book:
    print(number)

テキストの秘匿

機密情報(例:クレジットカード番号)を含むテキストから、正規表現を使用して情報を探し出し、マスクできます。

import re

def mask_credit_card_numbers(text):
    pattern = r'\b\d{4}-\d{4}-\d{4}-\d{4}\b'  # クレジットカード番号の正規表現パターン

    def mask(match):
        return '****-****-****-****'  # マスク後の形式

    masked_text = re.sub(pattern, mask, text)

    return masked_text

# テスト用のテキスト
text = '私のクレジットカード番号は1234-5678-9012-3456です。お支払いはお気をつけください。'

# クレジットカード番号をマスクする
masked_text = mask_credit_card_numbers(text)

# マスク後のテキストを表示
print(masked_text)

# 出力結果
# 私のクレジットカード番号は****-****-****-****です。お支払いはお気をつけください。

副詞の検索

文章から副詞を抽出するために、正規表現を使用してパターンマッチングを使います。

import re

def extract_adverbs(text):
    pattern = r'\b\w+ly\b'  # 副詞の正規表現パターン

    adverbs = re.findall(pattern, text)

    return adverbs

# テスト用の文章
text = '彼は静かにドアを開けた。彼女は大胆に挑戦した。彼らは慎重に計画を立てた。'

# 文章から副詞を抽出する
adverbs = extract_adverbs(text)

# 抽出された副詞を表示
print(adverbs)

まとめ

当記事では、Pythonと正規表現の基本的な関係について学習してきました。

  • 正規表現の基本的なパターン
  • Pythonのreモジュールの使い方
  • 文字列検索や置換の方法
  • グループ化やキャプチャ

これらの知識は、テキスト処理の作業を効率化し、データのクリーニングや解析を支援するための強力なツールです。

Pythonと正規表現の知識を深めるためには、実践的なプロジェクトに取り組むことがとても重要。

オンラインコースや書籍を活用し、コードを書く練習を積み重ねることが、スキルの向上につながります。

Pythonと正規表現の知識を活かして、効率的で洗練されたテキスト処理のソリューションを開発してください。

これはあなたのキャリアやプロジェクトに大きな価値をもたらすでしょう。

タイトルとURLをコピーしました