Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonで複数のドキュメント形式(CSV・テキスト・Word)から文字列を検索する方法

課題

異なる形式のファイルが多数保存されたディレクトリの中から、特定のキーワードを含むファイルを探したい場面はよくあります。本記事では、Pythonを使ってCSV、テキスト、MS Word(.docx)といった複数のドキュメント形式を横断的にスキャンし、目的の文字列を検索する方法を解説します。

事前準備

まず、以下のパッケージをインストールしておきましょう。

1. beautifulsoup4 … エンコーディング判定に使うUnicodeDammitのため

2. python-docx … Word文書を読み取るため

pip install beautifulsoup4 python-docx

実装方法

1. CSVファイル内の文字列検索関数

csv.readerモジュールを使ってファイルを1行ずつ読み込み、セルごとに文字列が含まれているかを確認します。見つかればTrue、なければFalseを返します。

def csv_stringsearch(input_file, input_string):
    """
    Function: search a string in csv files.
    args: input file , input string
    """
    with open(input_file) as file:
        for row in csv.reader(file):
            for column in row:
                if input_string in column.lower():
                    return True
    return False

2. テキストファイル内の文字列検索関数

テキストファイルの検索はやや厄介です。というのも、エンコーディングの問題に対処する必要があるためです。世の中には無数のエンコーディングが存在し、その判別はおそらく最も難しい部分です。もちろん、ファイルを作成した本人に直接聞けば済む話ですが、せっかく自動化するならここも自動で処理したいところですね。

そこで、BeautifulSoupに含まれるUnicodeDammitを使ってエンコーディングを推定します。

def text_stringsearch(input_file, input_string):
    """
    Function: search a string in text files.
    args: input file , input string
    """
    with open(input_file, 'rb') as file:
        content = file.read(1024)

    guessencoding = UnicodeDammit(content)
    encoding = guessencoding.original_encoding

    # Open and read
    with open(input_file, encoding=encoding) as file:
        for line in file:
            if input_string in line.lower():
                return True

    return False

3. MS Word文書内の文字列検索関数

python-docxライブラリを使えば、Word文書(.docx)の段落を簡単に走査できます。

def MSDocx_stringsearch(input_file, input_string):
    """
    Function: search a string in MS Word documents.
    args: input file , input string
    """
    doc = docx.Document(input_file)
    for paragraph in doc.paragraphs:
        if input_string in paragraph.text.lower():
            return True
    return False

4. メイン関数:ディレクトリを走査して各ファイルを検索

次に、os.walkでカレントディレクトリ以下を再帰的に巡回し、拡張子に応じて対応する検索関数を呼び出すメイン関数を作成します。ここではコードと検索対象ファイルが同じディレクトリにあると仮定しています。別の場所にある場合は、パス引数を追加すれば対応可能です。

def main(input_string):
    """
    Function: Open the current directory and search for a string in all the files
    args: input string
    """
    for root, dirs, files in os.walk('.'):
        for file in files:

            # Get the file extension
            extension = file.split('.')[-1]

            if extension in function_mapping:
                search_file = function_mapping.get(extension)
                full_file_path = os.path.join(root, file)

                if search_file(full_file_path, input_string):
                    print(f' *** Yeah String found in {full_file_path}')

5. 拡張子と関数のマッピング辞書

拡張子ごとに対応する検索関数を紐付ける辞書を作成します。

function_mapping = {
    'csv': csv_stringsearch,
    'txt': text_stringsearch,
    'docx': MSDocx_stringsearch,
}

6. 全体のコード

以上をすべてまとめた完全なコードがこちらです。

import os
import argparse
import csv
import docx
from bs4 import UnicodeDammit


def csv_stringsearch(input_file, input_string):
    """
    Function: search a string in csv files.
    args: input file , input string
    """
    with open(input_file) as file:
        for row in csv.reader(file):
            for column in row:
                if input_string in column.lower():
                    return True
    return False


def MSDocx_stringsearch(input_file, input_string):
    """
    Function: search a string in MS Word documents.
    args: input file , input string
    """
    doc = docx.Document(input_file)
    for paragraph in doc.paragraphs:
        if input_string in paragraph.text.lower():
            return True

    return False


def text_stringsearch(input_file, input_string):
    """
    Function: search a string in text files.
    args: input file , input string
    """
    with open(input_file, 'rb') as file:
        content = file.read(1024)

    guessencoding = UnicodeDammit(content)
    encoding = guessencoding.original_encoding

    # Open and read
    with open(input_file, encoding=encoding) as file:
        for line in file:
            if input_string in line.lower():
                return True

    return False


def main(input_string):
    """
    Function: Open the current directory and search for a string in all the files
    args: input string
    """
    for root, dirs, files in os.walk('.'):
        for file in files:

            # Get the file extension
            extension = file.split('.')[-1]

            if extension in function_mapping:
                search_file = function_mapping.get(extension)
                full_file_path = os.path.join(root, file)

                if search_file(full_file_path, input_string):
                    print(f' *** Yeah String found in {full_file_path}')


function_mapping = {
    'csv': csv_stringsearch,
    'txt': text_stringsearch,
    'docx': MSDocx_stringsearch,
}

if __name__ == '__main__':
    string_to_search = 'Hello'
    print(f'Output \n')
    main(string_to_search.lower())

実行結果

*** Yeah String found in .\Hello_World.docx
*** Yeah String found in .\My_Amazing_WordDoc.docx

7. コマンドライン実行への対応(argparse)

検索したい文字列を実行時に指定できるようにするには、argparseモジュールを利用します。

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-s', type=str, help='Input string to search', default='Hello')
    args = parser.parse_args()
    main(args.s.lower())

これで、python script.py -s "検索したい文字列" のように実行でき、任意のキーワードを柔軟に指定できるようになります。

  1. Word文書を復元する方法|クラッシュ・破損ファイルからの回復手順を徹底解説

    何時間もかけて書き上げた文書が、パソコンの突然のクラッシュで消えてしまった——そんな経験はありませんか?数千語に及ぶ文章と長時間の努力が一瞬で失われるのは、Microsoft Wordで文書を作成・編集している際に実際に起こり得るシナリオです。特に、ファイルを保存していない状態でクラッシュすると、被害は甚大になります。 しかし、希望はあります。Googleドキュメントと同様に、Wordにも自動保存機能が備わっており、ユーザーが自分で保存していなくても文書を自動的に保存してくれます。さらに、ファイルへの変更履歴の復元や、破損した文書の修復もサポートしています。ここでは、大切なWord文書を完全

  2. PythonでpandasのDataFrameをCSVファイルに書き込む方法【to_csv()の使い方】

    pandasのDataFrameをCSVファイルに出力する基本 PythonでpandasのDataFrameをCSVファイルに書き込むには、to_csv()メソッドを使用します。このメソッドは、DataFrameの内容をそのままCSV形式で保存できる、最もシンプルで一般的な方法です。 まずはサンプルデータとして、リストを値にもつ辞書を作成しましょう。 # リストの辞書を定義 d = {Car: [BMW, Lexus, Audi, Mercedes, Jaguar, Bentley], Date_of_purchase: [2020-10-10, 2020-10-12, 2020-