だいぶ前に書いた下記の記事
の内容がPython3で動かないようなので、
Python3対応しつつ、もう少し使えるように書きなおしてみる。
まずはPython3で動くように修正する。
import os import re search_dir = "<検索対象フォルダ>" search_pattern = "<検索パターン>" file_name_list = os.listdir(search_dir) for file_name in file_name_list: f = open(os.path.join(search_dir, file_name), encoding="utf-8") line = f.readline() line_number = 1 while line: m = re.search(search_pattern, line) if m: print("%s,%d : %s" % (file_name, line_number, line.strip())) line = f.readline() line_number = line_number + 1 f.close()
続いて、ファイル処理をwith内で行うように変更する。
import os import re search_dir = "<検索対象フォルダ>" search_pattern = "<検索パターン>" file_name_list = os.listdir(search_dir) for file_name in file_name_list: with open(os.path.join(search_dir, file_name), encoding="utf-8") as f: line_number = 1 for line in f: m = re.search(search_pattern, line) if m: print("%s,%d : %s" % (file_name, line_number, line.strip())) line_number = line_number + 1
ちょっとシンプルになった。
ディレクトリを無視する処理を追加する。
この処理がなかったのはひどい。
... for file_name in file_name_list: file_path = os.path.join(search_dir, file_name) if os.path.isdir(file_path): continue with open(file_path, encoding="utf-8") as f: line_number = 1 for line in f: m = re.search(search_pattern, line) if m: print("%s,%d : %s" % (file_name, line_number, line.strip())) line_number = line_number + 1
特定の拡張子のファイルのみ検索対象とする。
... ext_patterns = ( ".txt", ".py", ".csv", ".rst", ".md", ) file_name_list = os.listdir(search_dir) for file_name in file_name_list: file_path = os.path.join(search_dir, file_name) if os.path.isdir(file_path): continue _, ext = os.path.splitext(file_name) if not ext in ext_patterns: continue ...
文字コード自動判別機能を追加する。
chardetモジュールのインストールが必要。
下記を参照した:
pip install chardet
... from chardet.universaldetector import UniversalDetector ... def detect_encoding(file_path): detector = UniversalDetector() try: with open(file_path, mode="rb") as f: while True: data = f.readline() if data == b'': break detector.feed(data) if detector.done: break finally: detector.close() detected_encodings = detector.result return detected_encodings["encoding"] ... for file_name in file_name_list: ... encoding = detect_encoding(file_path) with open(file_path, encoding=encoding) as f: ...
サブディレクトリも検索できるように
os.walkを使うかどうか指定できるようにする。
あと、検索処理と表示処理を分離する。
今回はこれで完成とする。
# -*- coding: utf-8 -*- import os import re from chardet.universaldetector import UniversalDetector walk_subdirs = True search_dir = "<検索対象フォルダ>" search_pattern = "<検索パターン>" ext_patterns = ( ".txt", ".py", ".csv", ".rst", ".md", ) def detect_encoding(file_path): detector = UniversalDetector() try: with open(file_path, mode="rb") as f: while True: data = f.readline() if data == b'': break detector.feed(data) if detector.done: break finally: detector.close() detected_encodings = detector.result return detected_encodings["encoding"] def search_files(dir_path, file_name_list): matched_list = [] for file_name in file_name_list: _, ext = os.path.splitext(file_name) if not ext in ext_patterns: continue file_path = os.path.join(dir_path, file_name) encoding = detect_encoding(file_path) with open(file_path, encoding=encoding) as f: line_number = 1 for line in f: m = re.search(search_pattern, line) if m: file_info = { "path": file_path, "line_number": line_number, "line": line.strip() } matched_list.append(file_info) line_number = line_number + 1 return matched_list def print_matched_list(matched_list): for file_info in matched_list: print("%s,%d : %s" % (file_info["path"], file_info["line_number"], file_info["line"])) if walk_subdirs: matched_list = [] for root, dirs, files in os.walk(search_dir): sub_matched_list = search_files(root, files) matched_list.extend(sub_matched_list) else: file_name_list = os.listdir(search_dir) matched_list = search_files(search_dir, file_name_list) print_matched_list(matched_list)
おわり
Excelファイルの中身とかも検索できるようにできたら、
実用的なスクリプトになりそうだ。
- 作者: Bill Lubanovic,斎藤康毅,長尾高弘
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/12/01
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (3件) を見る