Pythonで文字列を抽出する方法:位置指定・正規表現による部分文字列取得

 

スライスによる位置指定抽出

基本的なスライス

text = "Python Programming"

# 先頭から6文字
first_part = text[:6]
print(first_part)  # Python

# 7文字目以降
second_part = text[7:]
print(second_part)  # Programming

# 7文字目から12文字目まで
middle_part = text[7:12]
print(middle_part)  # Progr

負のインデックス

text = "Hello, World!"

# 最後の6文字
last_part = text[-6:]
print(last_part)  # World!

# 最後から7文字目から最後から2文字目まで
middle = text[-7:-1]
print(middle)  # World

ステップを指定した抽出

text = "0123456789"

# 2文字おきに抽出
every_two = text[::2]
print(every_two)  # 02468

# 逆順で抽出
reversed_text = text[::-1]
print(reversed_text)  # 9876543210

文字数による抽出

固定文字数で分割

def extract_chunks(text, chunk_size):
    return  for i in range(0, len(text), chunk_size)]

text = "abcdefghijklmnop"
chunks = extract_chunks(text, 4)
print(chunks)  # ['abcd', 'efgh', 'ijkl', 'mnop']

先頭・末尾から指定文字数

text = "Python Programming Language"

# 先頭から10文字
head = text[:10]
print(head)  # Python Pro

# 末尾から8文字
tail = text[-8:]
print(tail)  # Language

区切り文字による抽出

partition()を使用した抽出

email = "user@example.com"
username, sep, domain = email.partition("@")
print(f"ユーザー名: {username}")  # user
print(f"ドメイン: {domain}")     # example.com

split()と組み合わせた抽出

csv_line = "田中,30,エンジニア,東京"
parts = csv_line.split(",")
name = parts[0]
age = parts[1]
print(f"名前: {name}, 年齢: {age}")

正規表現による抽出

re.search()による単一マッチ

import re

text = "今日の気温は25度です"
match = re.search(r'\d+', text)
if match:
    temperature = match.group()
    print(f"気温: {temperature}度")  # 気温: 25度

re.findall()による全てのマッチ

import re

text = "価格は1000円、送料は500円、税込み1650円です"
prices = re.findall(r'\d+', text)
print(prices)  # ['1000', '500', '1650']

グループキャプチャによる複数要素抽出

import re

text = "2024年8月6日の天気は晴れです"
match = re.search(r'(\d+)年(\d+)月(\d+)日', text)
if match:
    year, month, day = match.groups()
    print(f"年: {year}, 月: {month}, 日: {day}")

名前付きグループによる抽出

import re

log_line = "2024-08-06 12:30:45 INFO User login successful"
pattern = r'(?P<date>\d{4}-\d{2}-\d{2}) (?P<time>\d{2}:\d{2}:\d{2}) (?P<level>\w+) (?P<message>.*)'
match = re.match(pattern, log_line)

if match:
    print(f"日付: {match.group('date')}")
    print(f"時刻: {match.group('time')}")
    print(f"レベル: {match.group('level')}")
    print(f"メッセージ: {match.group('message')}")

実用的な活用例

URLからの情報抽出

import re

def extract_url_parts(url):
    pattern = r'https?://(?P<domain>[\w.-]+)(?P<path>/[\w/.-]*)?(?P<query>\?[\w&=.-]*)?'
    match = re.match(pattern, url)
    
    if match:
        return {
            'domain': match.group('domain'),
            'path': match.group('path') or '/',
            'query': match.group('query') or ''
        }
    return None

url = "https://www.example.com/path/to/page?param=value"
parts = extract_url_parts(url)
print(parts)

ファイルパスからの情報抽出

import os

def extract_file_info(filepath):
    # ディレクトリとファイル名を分離
    directory, filename = os.path.split(filepath)
    
    # ファイル名と拡張子を分離
    name, extension = os.path.splitext(filename)
    
    return {
        'directory': directory,
        'filename': filename,
        'name': name,
        'extension': extension[1:]  # ドットを除く
    }

path = "/home/user/documents/report.pdf"
info = extract_file_info(path)
print(info)

HTMLタグの内容抽出

import re

def extract_html_content(html, tag):
    pattern = f'<{tag}[^>]*>(.*?)</{tag}>'
    matches = re.findall(pattern, html, re.DOTALL)
    return matches

html = """
<div>
    <p>段落1です</p>
    <p>段落2です</p>
    <span>スパンです</span>
</div>
"""

paragraphs = extract_html_content(html, 'p')
print(paragraphs)  # ['段落1です', '段落2です']

CSVデータの列抽出

def extract_csv_column(csv_data, column_index):
    lines = csv_data.strip().split('\n')
    column_data = []
    
    for line in lines:
        parts = line.split(',')
        if len(parts) > column_index:
            column_data.append(parts[column_index])
    
    return column_data

csv_data = """名前,年齢,職業
田中,30,エンジニア
佐藤,25,デザイナー
鈴木,35,マネージャー"""

names = extract_csv_column(csv_data, 0)
print(names)  # ['名前', '田中', '佐藤', '鈴木']

電話番号の正規化

import re

def extract_phone_number(text):
    # 様々な形式の電話番号を抽出
    pattern = r'(\d{2,4})[- ]?(\d{4})[- ]?(\d{4})'
    match = re.search(pattern, text)
    
    if match:
        area, middle, last = match.groups()
        return f"{area}-{middle}-{last}"
    return None

texts = [
    "電話番号は 03 1234 5678 です",
    "連絡先: 090-9876-5432",
    "TEL: 06.2222.3333"
]

for text in texts:
    phone = extract_phone_number(text)
    print(f"{text} → {phone}")

複雑なパターンの抽出

ネストした構造の抽出

import re

def extract_nested_brackets(text):
    """括弧内の内容を抽出(ネスト対応)"""
    result = []
    level = 0
    start = -1
    
    for i, char in enumerate(text):
        if char == '(':
            if level == 0:
                start = i + 1
            level += 1
        elif char == ')':
            level -= 1
            if level == 0 and start != -1:
                result.append(text[start:i])
                start = -1
    
    return result

text = "関数(引数1, 関数2(内部引数))の呼び出し"
brackets = extract_nested_brackets(text)
print(brackets)  # ['引数1, 関数2(内部引数)']

JSONライクなデータの抽出

import re
import json

def extract_json_values(json_string, key):
    """JSON文字列から特定キーの値を抽出"""
    try:
        data = json.loads(json_string)
        return extract_nested_value(data, key)
    except:
        # 正規表現による簡易抽出
        pattern = f'"{key}"\\s*:\\s*"([^"]*)"'
        matches = re.findall(pattern, json_string)
        return matches

def extract_nested_value(data, key):
    """ネストした辞書から値を抽出"""
    if isinstance(data, dict):
        if key in data:
            return [data[key]]
        result = []
        for value in data.values():
            result.extend(extract_nested_value(value, key))
        return result
    elif isinstance(data, list):
        result = []
        for item in data:
            result.extend(extract_nested_value(item, key))
        return result
    return []

json_data = '{"user": {"name": "田中", "info": {"name": "太郎"}}}'
names = extract_json_values(json_data, "name")
print(names)  # ['田中', '太郎']

パフォーマンス比較

import time
import re

def benchmark_extraction():
    text = "The year 2024 has many events in March and April" * 1000
    
    # スライスによる抽出
    start = time.time()
    for _ in range(1000):
        result = text[10:20]
    time1 = time.time() - start
    
    # 正規表現による抽出
    pattern = re.compile(r'\d{4}')
    start = time.time()
    for _ in range(1000):
        matches = pattern.findall(text)
    time2 = time.time() - start
    
    print(f"スライス: {time1:.6f}秒")
    print(f"正規表現: {time2:.6f}秒")

benchmark_extraction()

まとめ

文字列抽出の方法を適切に選択することで、効率的なデータ処理が可能になります:

  • 単純な位置指定:スライス記法
  • 固定パターン:partition()split()
  • 複雑なパターン:正規表現(reモジュール)
  • 構造化データ:専用パーサーとの組み合わせ

用途と性能要件に応じて最適な抽出方法を選択することが重要です。

■プロンプトだけでオリジナルアプリを開発・公開してみた!!

■AI時代の第一歩!「AI駆動開発コース」はじめました!

テックジム東京本校で先行開始。

■テックジム東京本校

「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。

<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。

<月1開催>放送作家による映像ディレクター養成講座

<オンライン無料>ゼロから始めるPython爆速講座