【Python入門】re.sub()を完全マスター:正規表現で文字列を自在に置換する方法

python

Pythonで文字列を操作していると、「あるパターンに一致する部分をまとめて置き換えたい」という場面によく出くわします。

そんなときに力を発揮するのが、正規表現(regex)を使った置換処理re.sub()です。

replace()では対応できないような、より柔軟な条件付きの文字列置換も、re.sub()ならスマートに実現可能です。

本記事では、Pythonのre.sub()の使い方から、よくある活用例、注意点までを分かりやすく解説します。

スポンサーリンク

re.sub()の基本構文と仕組み

re.sub()とは?

re.sub()は、Pythonの標準ライブラリreに含まれる関数で、正規表現にマッチする文字列を指定の文字列で置換します。

まずはインポート

import re

基本の書き方

構文

re.sub(pattern, repl, string, count=0, flags=0)

パラメータの説明

  • pattern:置換対象となる正規表現のパターン
  • repl:置き換える文字列
  • string:処理対象の文字列
  • count:置換する最大回数(0の場合はすべて置換)
  • flags:検索オプション(例:re.IGNORECASE

基本例:単純な置換

コード例

import re

text = "Python is easy. Python is powerful."
result = re.sub("Python", "Java", text)
print(result)

結果

Java is easy. Java is powerful.

説明:文字列中の「Python」をすべて「Java」に置き換えています。

replace()との違い

replace()の場合

text = "Python is easy. Python is powerful."
result = text.replace("Python", "Java")
print(result)  # Java is easy. Java is powerful.

re.sub()の場合

import re

text = "Python is easy. Python is powerful."
result = re.sub("Python", "Java", text)
print(result)  # Java is easy. Java is powerful.

一見同じですが…

  • replace():完全一致のみ
  • re.sub():パターンマッチング(正規表現)が使える

置換回数を制限する

コード例

import re

text = "cat cat cat dog"
result = re.sub("cat", "mouse", text, count=2)
print(result)

結果

mouse mouse cat dog

説明count=2により、最初の2つの「cat」のみが置換されます。

まとめre.sub()の基本的な書き方が分かったところで、次は正規表現の活用による柔軟な置換について掘り下げていきます。

正規表現を使った高度な置換

数字のパターンを置換

コード例

import re

text = "User123 scored 98 points."
result = re.sub(r"\d+", "#", text)
print(result)

結果

User# scored # points.

説明

  • \d+:1つ以上の連続した数字にマッチ
  • r"...":生文字列(後で詳しく説明)

メールアドレスをマスクする

コード例

import re

text = "連絡先: info@example.com, support@test.org"
result = re.sub(r"\S+@\S+\.\S+", "[メール非表示]", text)
print(result)

結果

連絡先: [メール非表示], [メール非表示]

説明

  • \S+:空白以外の文字が1つ以上
  • @:アットマーク
  • \.:ドット(エスケープが必要)

電話番号の形式を統一

コード例

import re

text = "電話: 090-1234-5678, 03-9876-5432"
result = re.sub(r"(\d{2,4})-(\d{4})-(\d{4})", r"\1.\2.\3", text)
print(result)

結果

電話: 090.1234.5678, 03.9876.5432

説明

  • (\d{2,4}):2〜4桁の数字をグループ化
  • \1, \2, \3:キャプチャしたグループを参照

HTMLタグを削除

コード例

import re

html = "<p>こんにちは<br>世界</p>"
result = re.sub(r"<[^>]+>", "", html)
print(result)

結果

こんにちは世界

説明

  • <[^>]+><で始まり>で終わる、間に>以外の文字が1つ以上

単語の境界を利用した置換

コード例

import re

text = "cat catastrophe scattered"
# 単語の境界を使って「cat」のみを置換
result = re.sub(r"\bcat\b", "dog", text)
print(result)

結果

dog catastrophe scattered

説明

  • \b:単語境界
  • 完全な単語「cat」のみがマッチし、「catastrophe」の一部は置換されない

まとめ:正規表現を使うことで、単なる文字列の一致を超えてパターン認識に基づいた置換が可能になります。次は、関数を使った動的な置換を紹介します。

関数を使って置換をカスタマイズする

基本的な関数の使い方

re.sub()の2番目の引数に関数を渡すことで、マッチした内容に応じて置換の方法を動的に変更できます。

コード例

import re

def to_upper(match):
    """マッチした文字列を大文字に変換"""
    return match.group(0).upper()

text = "hello world python"
result = re.sub(r"\b\w+\b", to_upper, text)
print(result)

結果

HELLO WORLD PYTHON

説明

  • match.group(0):マッチした文字列全体を取得
  • \b\w+\b:単語境界に囲まれた1つ以上の単語文字

数字を2倍にする

コード例

import re

def double_number(match):
    """マッチした数字を2倍にする"""
    number = int(match.group(0))
    return str(number * 2)

text = "5個のりんごと3個のオレンジ"
result = re.sub(r"\d+", double_number, text)
print(result)

結果

10個のりんごと6個のオレンジ

より複雑な例:単語の長さで処理を変える

コード例

import re

def process_word(match):
    """単語の長さに応じて処理を変える"""
    word = match.group(0)
    if len(word) <= 3:
        return word.upper()  # 短い単語は大文字
    else:
        return word.lower()  # 長い単語は小文字

text = "The Quick Brown Fox Jumps"
result = re.sub(r"\b\w+\b", process_word, text)
print(result)

結果

THE quick brown FOX jumps

グループを使った高度な処理

コード例

import re

def format_date(match):
    """日付の形式を変換"""
    year = match.group(1)
    month = match.group(2)
    day = match.group(3)
    return f"{year}年{month}月{day}日"

text = "今日は2025-06-05です"
result = re.sub(r"(\d{4})-(\d{2})-(\d{2})", format_date, text)
print(result)

結果

今日は2025年06月05日です

説明

  • (\d{4})(\d{2}):それぞれがグループとしてキャプチャされる
  • match.group(1)match.group(2):各グループにアクセス

条件付き置換

コード例

import re

def conditional_replace(match):
    """条件に応じて置換を決める"""
    word = match.group(0)
    if word.startswith('P'):
        return 'Java'
    elif word.startswith('J'):
        return 'Python'
    else:
        return word

text = "Python Java C++ JavaScript"
result = re.sub(r"\b[A-Z]\w*", conditional_replace, text)
print(result)

結果

Java Python C++ Python

まとめre.sub()に関数を渡すことで、単なる置換を超えて、内容に応じた柔軟な処理が可能になります。最後に、よくあるミスや注意点を紹介します。

re.sub()を使う上での注意点とコツ

生文字列(raw string)を使う

問題のあるコード

import re

# バックスラッシュが正しく解釈されない可能性
text = "test\nstring"
result = re.sub("\n", " ", text)  # 動くが推奨されない

推奨されるコード

import re

text = "test\nstring"
result = re.sub(r"\n", " ", text)  # r"..." を使用
print(repr(result))  # 'test string'

説明r"..."(生文字列)を使うことで、バックスラッシュが正規表現として正しく解釈されます。

大文字小文字を無視する

コード例

import re

text = "Python python PyThOn PYTHON"
result = re.sub("python", "Java", text, flags=re.IGNORECASE)
print(result)

結果

Java Java Java Java

説明flags=re.IGNORECASEにより、大文字小文字を区別せずにマッチします。

よくあるエラーと対処法

エラー1:意図しない部分がマッチしてしまう

問題のあるコード

import re

text = "cats and dogs"
result = re.sub("cat", "mouse", text)
print(result)  # mouseS and dogs(不適切)

修正後

import re

text = "cats and dogs"
result = re.sub(r"\bcat\b", "mouse", text)
print(result)  # cats and dogs(catは単語として存在しない)

# または、複数形も考慮
result = re.sub(r"\bcats?\b", "mouse", text)
print(result)  # mouse and dogs

エラー2:特殊文字のエスケープ忘れ

問題のあるコード

import re

text = "価格: $100.50"
result = re.sub("$", "¥", text)  # $は正規表現では行末を意味する
print(result)  # 期待通りに動かない

修正後

import re

text = "価格: $100.50"
result = re.sub(r"\$", "¥", text)  # エスケープが必要
print(result)  # 価格: ¥100.50

エラー3:グループ参照の間違い

問題のあるコード

import re

text = "2025-06-05"
result = re.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\3/\2/\1", text)
print(result)  # 05/06/2025(日/月/年の順)

意図したコード

import re

text = "2025-06-05"
result = re.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\2/\3/\1", text)
print(result)  # 06/05/2025(月/日/年の順)

パフォーマンスを考慮した使い方

同じパターンを何度も使う場合

非効率な方法

import re

texts = ["text1", "text2", "text3"] * 1000

results = []
for text in texts:
    result = re.sub(r"\d+", "#", text)  # 毎回コンパイル
    results.append(result)

効率的な方法

import re

# パターンを事前にコンパイル
pattern = re.compile(r"\d+")
texts = ["text1", "text2", "text3"] * 1000

results = []
for text in texts:
    result = pattern.sub("#", text)  # コンパイル済みを再利用
    results.append(result)

実践的な使用例

ログファイルの整形

コード例

import re

def clean_log_line(match):
    """ログの不要な情報を削除"""
    timestamp = match.group(1)
    level = match.group(2)
    message = match.group(3)
    
    # DEBUGレベルは除外
    if level == "DEBUG":
        return ""
    
    return f"[{timestamp}] {level}: {message}"

log_text = """
2025-06-05 10:00:01 INFO User logged in
2025-06-05 10:00:02 DEBUG Database query executed
2025-06-05 10:00:03 ERROR Connection failed
"""

result = re.sub(
    r"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) (\w+) (.+)",
    clean_log_line,
    log_text
)
print(result)

HTMLエスケープ

コード例

import re

def html_escape(match):
    """HTMLの特殊文字をエスケープ"""
    char = match.group(0)
    escape_dict = {
        '<': '&lt;',
        '>': '&gt;',
        '&': '&amp;',
        '"': '&quot;',
        "'": '&#x27;'
    }
    return escape_dict.get(char, char)

text = '<div>Hello "World" & Friends</div>'
result = re.sub(r'[<>&"\']', html_escape, text)
print(result)
# &lt;div&gt;Hello &quot;World&quot; &amp; Friends&lt;/div&gt;

よく使うパターン集

用途パターン
数字r"\d+"re.sub(r"\d+", "#", text)
メールアドレスr"\S+@\S+\.\S+"re.sub(r"\S+@\S+\.\S+", "[email]", text)
HTMLタグr"<[^>]+>"re.sub(r"<[^>]+>", "", html)
空白の正規化r"\s+"re.sub(r"\s+", " ", text)
電話番号r"\d{2,4}-\d{4}-\d{4}"re.sub(r"(\d+)-(\d+)-(\d+)", r"\1.\2.\3", text)

まとめ:re.sub()で文字列処理をマスターしよう!

重要なポイント

基本的な使い方

  • re.sub(pattern, repl, string)で基本的な置換
  • 正規表現を使ってパターンマッチングが可能
  • countパラメータで置換回数を制限できる

応用的な使い方

  • 関数を渡して動的な置換が可能
  • グループキャプチャで部分的な情報を活用
  • フラグを使って大文字小文字を無視などの条件設定

注意すべきポイント

  • 生文字列(r"...")を使用してエスケープ問題を回避
  • 特殊文字は適切にエスケープする
  • パフォーマンスを考慮してパターンをコンパイル

使い分けガイド

用途推奨方法理由
単純な文字列置換str.replace()高速で分かりやすい
パターンベースの置換re.sub()柔軟性が高い
動的な置換re.sub() + 関数条件に応じた処理が可能
大量データの処理re.compile() + sub()パフォーマンスが良い

実践での活用場面

データクレンジング

  • ログファイルの整形
  • HTMLタグの除去
  • 不要な文字の削除

フォーマット変換

  • 日付形式の統一
  • 電話番号の形式変更
  • 通貨記号の変換

セキュリティ対策

  • 個人情報のマスキング
  • HTMLエスケープ処理
  • SQLインジェクション対策

コメント

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