22行のPythonコードでWordのgrepコマンドを作る
22行のPythonコードでWordのgrepコマンドを作る

22行のPythonコードでWordのgrepコマンドを作る

設計書を書く上で最も使用されているフォーマットは、Microsoft Officeの「Word」が提供している「docx」拡張子であることは言うまでもないでしょう。

 

「Word」ファイルの欠点としては、textファイルのようにgrepして検索できない問題点が挙げられます。

 

そこで、「Python 3」の「python-docx」を使用したdocx用grep機能を作成してみました。

 

ソースコードの全体

今回作成したソースコードの全体がこちらとなります。

 

# -*- coding: utf-8 -*-
from docx import Document
import glob
import sys

argvs = sys.argv
argc = len(argvs)

if (argc != 3): 
    print('引数が足りません. 検索文字 検索先')
    quit()         # プログラムの終了

files = glob.glob(argvs[2] + '/**/*.docx', recursive=True)

for fil in files:
    document = Document(fil)
    count =0
    for para in document.paragraphs:
        count+=1
        if para.text.find( argvs[1]) > -1:
            print(fil + ":" + '行数' + str(count) + ':' + para.text)

 

このようにdocxファイルのgrep機能は、22行で作成することができます。

(少ないコードで機能を実装できるPythonはいいですね)

 

今回使用するモジュールは、以下の通りとなります。

 

  • python-docx
  • glob
  • Document
  • sys

 

始める前に必要なライブラリをpipでインストールしましょう!

 

まずは、メインで使用する「python-docx」が入っていなければ、以下のコマンドでインストールすることができます。

 

 pip install python-docx

 

コードの解説

 

インポートと文字コード

一行目に文字コードを宣言した上で、必要なライブラリをインポートします。

 

# -*- coding: utf-8 -*-
from docx import Document
import glob
import sys

 

今回は、python-docxを使用するのですが、「docx」ファイルを読み込むためにDocumentを宣言しております。

 

目指すべき処理としては、「glob」によりファイルの一覧を取得し、Documentで「docx」の中身を取り出す流れとなります。

 

引数の受け取りとチェック処理

引数を受け取るために「sys」から値を取得します。

 

argvs = sys.argv
argc = len(argvs)

 

「argvs」を宣言し、値を取るための変数を作成します。

 

「argc」は、引数の数が足りているかチェックを行うための変数となります。

 

以下が「argc」を使用した引数のチェック処理となります。

 

if (argc != 3):
    print('引数が足りません. 検索文字 検索先')
    quit()         # プログラムの終了
 

今回のプログラムでは、引数は以下の2つが必要となります。

 

  • 検索キーワード
  • 検索するフォルダ

 

そのため、if文にて「argc」の長さが3ではない時にエラーとなるようなチェックを行っております。

 

チェック処理によりエラーとなった場合は、エラーメッセージの表示後、「quit()」でプログラムを終了します。

 

フォルダ階層を再帰的に検索し、配列として持つ

指定したフォルダからファイルを配列として持つために「glob」を使用します。

 

files = glob.glob(argvs[2] + '/**/*.docx', recursive=True)

 

再帰的にフォルダの中からファイルを取得する処理は、「recursive=True」を指定することで実装可能です。

 

検索する処理は正規表現を利用して得られるため、Pythonの引数である「argvs[2]」から正規表現でdocxファイルの一覧を取得します。

 

この一行により、「glob.glob」で指定したフォルダ階層にあるdocxファイルを配列として持つことができます。

 

glob配列をループして文字列を検索

globにて得られたdocxファイルの配列を1ファイルずつ1行ごとに文字検索しながらループします。

 

for fil in files:
    document = Document(fil)
    count =0
    for para in document.paragraphs:
        count+=1
        if para.text.find( argvs[1]) > -1:
            print(fil + ":" + '行数' + str(count) + ':' + para.text)

 

pipでインストールしたpython-docxを使用するために、「Document」へ「ファイル一覧」が格納された配列を渡します。

 

「document.paragraphs」でワードの文字列を行ごとに配列として格納することができます。

 

1番目のループ処理内になる2行目のカウントは、ヒットしたキーワードがWordファイルの何行目にあたるのか確認するために宣言しております。

 

2番目のループでは、配列化された「Word」の文章の長さで回し、「find」で配列の中に検索値(引数)があるかを判定しております。

 

判定結果により検索値が含まれていた場合は、行数と該当配列の中身(該当行)を出力します。

 

基本的に「python [ファイル名].py [検索キーワード] [対象フォルダ]」で利用することができますが、よく使うのであれば「.bashrc」のaliasに登録すると良いでしょう。

 

alias wordgrep="python [ファイル階層]/[ファイル名].py  $@ "

 

課題

22行という少ないコードで実装することができたが、「python-docx」に依存しているため、古い拡張子である「doc」などは検索することができません。

 

また、grepをベースとして考えているため、ページ数ではなく行数でOutPutされるため、該当行を探すことが困難です。

 

あるあるですが、フォルダ構造のチェック処理などの文字列チェックがあれば、なお良いと思います。

  • .