Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

Python으로 CSV·텍스트·MS Word 등 다양한 문서 형식에서 문자열 검색하기

문제 상황

여러 형식의 파일이 가득한 디렉터리가 있고, 그 안에서 특정 키워드를 찾아야 한다고 가정해 보겠습니다. 파일 확장자마다 읽는 방식이 다르기 때문에 일일이 열어 확인하는 것은 비효율적입니다. 이 글에서는 Python으로 이 과정을 자동화하는 방법을 단계별로 살펴봅니다.

사전 준비

먼저 아래 두 패키지를 설치합니다.

1. beautifulsoup4 — 텍스트 파일의 인코딩을 자동으로 판별하는 UnicodeDammit 기능을 사용하기 위해 필요합니다.

2. python-docx — MS Word(.docx) 문서를 읽고 처리하기 위해 필요합니다.

pip install beautifulsoup4 python-docx

구현 방법

1. CSV 파일에서 문자열 검색하기

csv.reader 모듈을 사용해 파일을 행 단위로 읽어 들이고, 각 셀(column)에 검색할 문자열이 포함되어 있는지 확인합니다. 문자열을 찾으면 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. 텍스트 파일에서 문자열 검색하기

텍스트 파일 검색은 인코딩 문제 때문에 다소 까다롭습니다. 세상에는 수천 가지 인코딩이 존재하며, 파일의 인코딩 형식을 정확히 파악하는 것이 가장 어려운 부분입니다. 파일을 만든 사람에게 직접 물어볼 수도 있지만, 우리의 목표는 자동화이므로 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

    # 판별된 인코딩으로 파일을 열고 읽기
    with open(input_file, encoding=encoding) as file:
        for line in file:
            if input_string in line.lower():
                return True

    return False

파일의 첫 1024바이트만 샘플로 읽어 인코딩을 추론한 뒤, 해당 인코딩으로 전체 파일을 다시 여는 방식입니다. 대부분의 경우 이 방법만으로도 충분히 정확하게 인코딩을 판별할 수 있습니다.

3. MS Word 문서에서 문자열 검색하기

python-docx 라이브러리를 사용하면 .docx 파일의 모든 문단(paragraph)을 손쉽게 순회하며 문자열을 검색할 수 있습니다.

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. 메인 함수 작성하기

이제 디렉터리 내 모든 파일을 순회하면서, 확장자에 맞는 검색 함수를 호출하는 메인 함수가 필요합니다. 여기서는 코드와 검색 대상 파일이 같은 디렉터리에 있다고 가정합니다. 만약 파일들이 다른 위치에 있다면 경로(path) 매개변수를 추가하면 됩니다.

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:

            # 파일 확장자 추출
            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. 명령줄 인터페이스(CLI)로 실행하기

검색할 문자열을 코드에 하드코딩하지 않고 명령줄에서 직접 입력받고 싶다면 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 search_tool.py -s "찾을문자열"

마무리

이처럼 Python을 활용하면 CSV, 텍스트, MS Word 등 서로 다른 형식의 문서를 하나의 스크립트로 통합 검색할 수 있습니다. 핵심은 확장자별 검색 함수를 딕셔너리로 매핑하는 구조인데, 덕분에 PDF나 Excel 같은 새로운 형식도 함수만 추가하면 손쉽게 지원 범위를 넓힐 수 있습니다. 대용량 문서 아카이브에서 특정 키워드를 찾아야 하는 업무 자동화에 유용하게 활용해 보세요.