Pythonでファイル内文字列検索!grep的処理で特定行を抽出する方法

 

Pythonでファイル内の特定文字列を含む行を抽出する処理は、ログ解析やデータ処理で頻繁に使用されます。本記事では、Unix/Linuxのgrepコマンドのような機能をPythonで実現する方法を詳しく解説します。

基本的な文字列検索・抽出

特定文字列を含む行の抽出

# ファイルから特定文字列を含む行を抽出
def grep_lines(filename, search_text):
    with open(filename, 'r', encoding='utf-8') as f:
        for line_num, line in enumerate(f, 1):
            if search_text in line:
                print(f'{line_num}: {line.strip()}')

# 使用例
grep_lines('log.txt', 'ERROR')

抽出結果をリストで取得

def find_matching_lines(filename, search_text):
    matches = []
    with open(filename, 'r', encoding='utf-8') as f:
        for line_num, line in enumerate(f, 1):
            if search_text in line:
                matches.append({'line_num': line_num, 'content': line.strip()})
    return matches

# 使用例
results = find_matching_lines('data.txt', 'Python')
for result in results:
    print(f"行 {result['line_num']}: {result['content']}")

正規表現を使った高度な検索

正規表現パターンマッチング

import re

def grep_regex(filename, pattern):
    regex = re.compile(pattern)
    with open(filename, 'r', encoding='utf-8') as f:
        for line_num, line in enumerate(f, 1):
            if regex.search(line):
                print(f'{line_num}: {line.strip()}')

# IPアドレスを含む行を検索
grep_regex('access.log', r'\d+\.\d+\.\d+\.\d+')

大文字小文字を区別しない検索

import re

def case_insensitive_grep(filename, search_text):
    pattern = re.compile(search_text, re.IGNORECASE)
    with open(filename, 'r', encoding='utf-8') as f:
        for line_num, line in enumerate(f, 1):
            if pattern.search(line):
                print(f'{line_num}: {line.strip()}')

# 使用例
case_insensitive_grep('text.txt', 'error')

複数条件での検索

AND条件(複数キーワードすべてを含む)

def grep_all_keywords(filename, keywords):
    with open(filename, 'r', encoding='utf-8') as f:
        for line_num, line in enumerate(f, 1):
            if all(keyword in line for keyword in keywords):
                print(f'{line_num}: {line.strip()}')

# 'ERROR'と'database'両方を含む行を検索
grep_all_keywords('app.log', ['ERROR', 'database'])

OR条件(いずれかのキーワードを含む)

def grep_any_keywords(filename, keywords):
    with open(filename, 'r', encoding='utf-8') as f:
        for line_num, line in enumerate(f, 1):
            if any(keyword in line for keyword in keywords):
                print(f'{line_num}: {line.strip()}')

# 'ERROR'または'WARNING'を含む行を検索
grep_any_keywords('app.log', ['ERROR', 'WARNING'])

実践的な使用例

ログファイル解析

from datetime import datetime

def analyze_log(filename, error_level='ERROR'):
    error_count = 0
    errors = []
    
    with open(filename, 'r', encoding='utf-8') as f:
        for line_num, line in enumerate(f, 1):
            if error_level in line:
                error_count += 1
                errors.append({
                    'line': line_num,
                    'content': line.strip(),
                    'timestamp': line.split()[0] if line.split() else 'N/A'
                })
    
    print(f'{error_level}レベルのエントリ: {error_count}件')
    return errors

# エラーログの解析
errors = analyze_log('application.log', 'ERROR')

CSVファイルの特定条件抽出

import csv

def grep_csv(filename, column_name, search_value):
    matches = []
    with open(filename, 'r', encoding='utf-8') as f:
        reader = csv.DictReader(f)
        for row_num, row in enumerate(reader, 2):  # ヘッダー行の次から
            if search_value in str(row.get(column_name, '')):
                matches.append({'row': row_num, 'data': row})
    return matches

# 名前列に'田中'を含む行を検索
results = grep_csv('users.csv', '名前', '田中')

高性能な大容量ファイル処理

メモリ効率的な検索

def efficient_grep(filename, search_text, max_results=None):
    count = 0
    with open(filename, 'r', encoding='utf-8') as f:
        for line_num, line in enumerate(f, 1):
            if search_text in line:
                yield {'line_num': line_num, 'content': line.strip()}
                count += 1
                if max_results and count >= max_results:
                    break

# 最初の10件のみ取得
for match in efficient_grep('large_file.txt', 'keyword', max_results=10):
    print(f"行 {match['line_num']}: {match['content']}")

結果の保存

検索結果をファイルに出力

def grep_to_file(input_file, output_file, search_text):
    match_count = 0
    with open(input_file, 'r', encoding='utf-8') as infile, \
         open(output_file, 'w', encoding='utf-8') as outfile:
        
        for line_num, line in enumerate(infile, 1):
            if search_text in line:
                outfile.write(f'{line_num}: {line}')
                match_count += 1
    
    print(f'{match_count}行を{output_file}に出力しました')

# 検索結果をファイルに保存
grep_to_file('input.log', 'errors.txt', 'ERROR')

pathlib.Pathを使った現代的なアプローチ

from pathlib import Path

def modern_grep(file_path, search_text):
    path = Path(file_path)
    if not path.exists():
        print(f'ファイルが見つかりません: {file_path}')
        return []
    
    lines = path.read_text(encoding='utf-8').splitlines()
    matches = []
    
    for line_num, line in enumerate(lines, 1):
        if search_text in line:
            matches.append({'line_num': line_num, 'content': line})
    
    return matches

# 使用例
results = modern_grep('data.txt', 'Python')

まとめ

Pythonでファイル内の文字列検索を行う際は、基本的なin演算子から正規表現まで、用途に応じて適切な手法を選択することが重要です。大容量ファイルの処理では、メモリ効率を考慮したジェネレータを使用し、複雑な条件での検索には正規表現を活用することで、柔軟で高性能なgrep的処理が実現できます。

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

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

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

■テックジム東京本校

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

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

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

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