[Python] 正規表現で文字列のリストから抽出する方法

Pythonで正規表現を使用して文字列のリストから特定のパターンを抽出するには、reモジュールを使用します。

まず、re.compile()で正規表現パターンをコンパイルし、次にre.match()re.search()re.findall()などを使ってリスト内の各文字列に対してパターンを適用します。

例えば、re.findall()はリスト内の各文字列からすべての一致を抽出するのに便利です。

リスト全体に対しては、リスト内包表記やfilter()を使うことができます。

この記事でわかること
  • 正規表現を使った抽出方法
  • 複雑なパターンの扱い方
  • パフォーマンス最適化の手法
  • 実践的なサンプルコードの活用

目次から探す

文字列のリストから正規表現で抽出する方法

Pythonでは、正規表現を使って文字列のリストから特定のパターンを抽出することができます。

以下に、いくつかの方法を紹介します。

リスト内包表記を使った抽出

リスト内包表記を使用すると、簡潔に特定のパターンに一致する要素を抽出できます。

以下は、数字を含む文字列を抽出する例です。

import re
# サンプルデータ
string_list = ["apple123", "banana", "cherry456", "date"]
# 数字を含む文字列を抽出
result = [s for s in string_list if re.search(r'\d+', s)]
print(result)
['apple123', 'cherry456']

filter()関数を使った抽出

filter()関数を使うことで、条件に一致する要素を抽出することも可能です。

以下は、特定のパターンに一致する文字列を抽出する例です。

import re
# サンプルデータ
string_list = ["apple123", "banana", "cherry456", "date"]
# 数字を含む文字列を抽出
result = list(filter(lambda s: re.search(r'\d+', s), string_list))
print(result)
['apple123', 'cherry456']

re.findall()を使ったリスト内の全一致抽出

re.findall()を使用すると、リスト内の各文字列から全ての一致を抽出できます。

以下は、文字列内の全ての数字を抽出する例です。

import re
# サンプルデータ
string_list = ["apple123", "banana456", "cherry789"]
# 各文字列から全ての数字を抽出
result = [re.findall(r'\d+', s) for s in string_list]
print(result)
[['123'], ['456'], ['789']]

re.search()を使った部分一致の抽出

re.search()を使うことで、部分一致する文字列を抽出することができます。

以下は、特定の文字列を含む要素を抽出する例です。

import re
# サンプルデータ
string_list = ["apple123", "banana", "cherry456", "date"]
# "cherry"を含む文字列を抽出
result = [s for s in string_list if re.search(r'cherry', s)]
print(result)
['cherry456']

re.match()を使った先頭一致の抽出

re.match()を使用すると、文字列の先頭が特定のパターンに一致するかどうかを確認できます。

以下は、先頭が”apple”で始まる文字列を抽出する例です。

import re
# サンプルデータ
string_list = ["apple123", "banana", "apple456", "date"]
# "apple"で始まる文字列を抽出
result = [s for s in string_list if re.match(r'apple', s)]
print(result)
['apple123', 'apple456']

よく使われる正規表現パターンの例

正規表現は、特定のパターンに基づいて文字列を検索・抽出するための強力なツールです。

ここでは、よく使われる正規表現パターンの例を紹介します。

数字やアルファベットの抽出

数字やアルファベットを抽出するための基本的な正規表現パターンは以下の通りです。

  • 数字:\d+
  • アルファベット:[a-zA-Z]+

以下は、文字列から数字とアルファベットを抽出する例です。

import re
# サンプルデータ
string = "abc123def456ghi789"
# 数字を抽出
numbers = re.findall(r'\d+', string)
# アルファベットを抽出
alphabets = re.findall(r'[a-zA-Z]+', string)
print("数字:", numbers)
print("アルファベット:", alphabets)
数字: ['123', '456', '789']
アルファベット: ['abc', 'def', 'ghi']

特定の文字列パターンの抽出

特定の文字列パターンを抽出するためには、具体的な文字列を正規表現に含めます。

例えば、”error”という単語を含む行を抽出する場合は以下のようにします。

import re
# サンプルデータ
log_data = """
2023-01-01 12:00:00 INFO Starting process
2023-01-01 12:01:00 ERROR Something went wrong
2023-01-01 12:02:00 INFO Process completed
"""
# "ERROR"を含む行を抽出
error_lines = re.findall(r'.*ERROR.*', log_data)
print("エラーメッセージ:", error_lines)
エラーメッセージ: ['2023-01-01 12:01:00 ERROR Something went wrong']

メールアドレスやURLの抽出

メールアドレスやURLを抽出するための正規表現は少し複雑ですが、以下のように記述できます。

  • メールアドレス:[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}
  • URL:https?://[^\s]+

以下は、メールアドレスとURLを抽出する例です。

import re
# サンプルデータ
text = "お問い合わせは info@example.com まで。ウェブサイトは https://www.example.com です。"
# メールアドレスを抽出
emails = re.findall(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', text)
# URLを抽出
urls = re.findall(r'https?://[^\s]+', text)
print("メールアドレス:", emails)
print("URL:", urls)
メールアドレス: ['info@example.com']
URL: ['https://www.example.com']

日付や電話番号の抽出

日付や電話番号を抽出するための正規表現もよく使用されます。

以下は、一般的なパターンの例です。

  • 日付(YYYY-MM-DD形式):\d{4}-\d{2}-\d{2}
  • 電話番号(日本の形式):0\d{1,4}-\d{1,4}-\d{4}

以下は、日付と電話番号を抽出する例です。

import re
# サンプルデータ
text = "日付は2023-01-01です。電話番号は03-1234-5678です。"
# 日付を抽出
dates = re.findall(r'\d{4}-\d{2}-\d{2}', text)
# 電話番号を抽出
phone_numbers = re.findall(r'0\d{1,4}-\d{1,4}-\d{4}', text)
print("日付:", dates)
print("電話番号:", phone_numbers)
日付: ['2023-01-01']
電話番号: ['03-1234-5678']

応用例:複雑なパターンの抽出

正規表現を使った文字列の抽出は、単純なパターンだけでなく、複雑な条件を組み合わせることでより強力になります。

ここでは、いくつかの応用例を紹介します。

複数の条件を組み合わせた抽出

複数の条件を組み合わせることで、より特定のパターンを抽出できます。

例えば、数字を含む文字列で、かつ特定の文字列(例:”apple”)を含むものを抽出する場合は以下のようにします。

import re
# サンプルデータ
string_list = ["apple123", "banana456", "apple456", "cherry789"]
# "apple"を含み、数字を含む文字列を抽出
result = [s for s in string_list if re.search(r'apple.*\d+', s)]
print(result)
['apple123', 'apple456']

グループ化とキャプチャを使った抽出

グループ化を使うことで、特定の部分をキャプチャし、後で利用することができます。

以下は、日付から年、月、日を抽出する例です。

import re
# サンプルデータ
text = "2023-01-01, 2024-02-02, 2025-03-03"
# 年、月、日をキャプチャ
dates = re.findall(r'(\d{4})-(\d{2})-(\d{2})', text)
print("キャプチャした日付:", dates)
キャプチャした日付: [('2023', '01', '01'), ('2024', '02', '02'), ('2025', '03', '03')]

re.sub()を使ったリスト内の文字列置換

re.sub()を使用すると、特定のパターンに一致する部分を置換することができます。

以下は、文字列内の数字を”NUM”に置換する例です。

import re
# サンプルデータ
string_list = ["apple123", "banana456", "cherry789"]
# 数字を"NUM"に置換
result = [re.sub(r'\d+', 'NUM', s) for s in string_list]
print(result)
['appleNUM', 'bananaNUM', 'cherryNUM']

フラグを使った大文字小文字の無視や複数行対応

正規表現のフラグを使うことで、大文字小文字を無視したり、複数行に対応したりすることができます。

以下は、大文字小文字を無視して”apple”を抽出する例です。

import re
# サンプルデータ
text = "Apple is a fruit. apple is also a fruit."
# 大文字小文字を無視して"apple"を抽出
result = re.findall(r'apple', text, re.IGNORECASE)
print("抽出した単語:", result)
抽出した単語: ['Apple', 'apple']

また、複数行に対応する場合は、re.MULTILINEフラグを使用します。

以下は、複数行のテキストから特定のパターンを抽出する例です。

import re
# サンプルデータ
text = """This is a test.
This is only a test.
apple is a fruit."""
# "apple"を含む行を抽出
result = re.findall(r'.*apple.*', text, re.MULTILINE)
print("含まれる行:", result)
含まれる行: ['apple is a fruit.']

パフォーマンスの最適化

正規表現を使用する際、パフォーマンスを最適化することは非常に重要です。

特に、大量のデータを扱う場合や複雑なパターンを使用する場合、効率的な方法を選ぶことで処理速度を向上させることができます。

以下に、正規表現のパフォーマンスを最適化する方法を紹介します。

正規表現のコンパイルによる高速化

正規表現を何度も使用する場合、re.compile()を使って正規表現をコンパイルすることで、処理速度を向上させることができます。

コンパイルされた正規表現は、内部で最適化されるため、再利用時のオーバーヘッドが減少します。

import re
# 正規表現をコンパイル
pattern = re.compile(r'\d+')
# サンプルデータ
string_list = ["apple123", "banana456", "cherry789"]
# コンパイルしたパターンを使って抽出
result = [s for s in string_list if pattern.search(s)]
print(result)
['apple123', 'banana456', 'cherry789']

大量のデータに対する正規表現の適用

大量のデータに対して正規表現を適用する場合、効率的な方法を選ぶことが重要です。

例えば、リスト内包表記やfilter()関数を使用することで、メモリの使用量を抑えつつ、処理を行うことができます。

import re
# 大量のサンプルデータ
string_list = ["apple123"] * 100000 + ["banana456"] * 100000 + ["cherry789"] * 100000
# 数字を含む文字列を抽出
result = [s for s in string_list if re.search(r'\d+', s)]
print("抽出した数:", len(result))
抽出した数: 300000

re.finditer()を使ったメモリ効率の向上

re.finditer()を使用すると、マッチオブジェクトのイテレータを返すため、メモリ効率が向上します。

特に、大量の一致を処理する場合に有効です。

以下は、re.finditer()を使った例です。

import re
# サンプルデータ
text = "apple123 banana456 cherry789 apple456"
# 数字を含む部分をイテレータで取得
matches = re.finditer(r'\d+', text)
# マッチした部分をリストに格納
result = [match.group() for match in matches]
print("抽出した数字:", result)
抽出した数字: ['123', '456', '789', '456']

このように、re.finditer()を使用することで、全てのマッチを一度にメモリに保持することなく、効率的に処理することができます。

これにより、大量のデータを扱う際のメモリ使用量を削減できます。

よくある質問

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

re.match()re.search()は、どちらも正規表現を使って文字列を検索するための関数ですが、主な違いは検索の範囲にあります。

  • re.match(): 文字列の先頭からパターンに一致するかどうかを確認します。

先頭が一致しない場合は、マッチしません。

  • re.search(): 文字列全体を対象にパターンに一致する部分を探します。

文字列のどこにでも一致があれば、マッチします。

import re
text = "apple123"
# re.match()は先頭から一致を確認
match_result = re.match(r'apple', text)  # 一致する
search_result = re.search(r'123', text)   # 一致する
print("match:", match_result is not None)  # True
print("search:", search_result is not None)  # True

正規表現で大文字小文字を区別しない方法は?

正規表現で大文字小文字を区別しない検索を行うには、re.IGNORECASEフラグを使用します。

このフラグを指定することで、検索時に大文字と小文字を区別せずに一致を確認できます。

import re
text = "Apple is a fruit."
# 大文字小文字を区別せずに"apple"を検索
result = re.search(r'apple', text, re.IGNORECASE)
print("一致したか:", result is not None)  # True

リスト内のすべての一致を一度に取得するには?

リスト内のすべての一致を一度に取得するには、re.findall()を使用することが一般的です。

この関数は、指定したパターンに一致するすべての部分をリストとして返します。

import re
# サンプルデータ
string_list = ["apple123", "banana456", "cherry789"]
# 各文字列から数字をすべて抽出
all_numbers = [re.findall(r'\d+', s) for s in string_list]
# 結果をフラットにする
flat_numbers = [num for sublist in all_numbers for num in sublist]
print("抽出した数字:", flat_numbers)
抽出した数字: ['123', '456', '789']

このように、re.findall()を使うことで、リスト内の各文字列からすべての一致を簡単に取得することができます。

まとめ

この記事では、Pythonにおける正規表現の基本的な使い方から、複雑なパターンの抽出方法、パフォーマンスの最適化に至るまで、さまざまなテクニックを紹介しました。

正規表現を活用することで、文字列の処理が効率的かつ柔軟に行えるようになりますので、ぜひ実際のプロジェクトで試してみてください。

正規表現の力を活かして、データ処理やテキスト解析のスキルを向上させていきましょう。

  • URLをコピーしました!
目次から探す