Excelからテキストを抽出する

C#.net

Excelファイルからテキストを抽出する

Windows 10 / Visual Stadio Community 2019 / .NET Framework 4.7.2
Excelファイルの全文検索を行うためには、Excel形式の内部データからテキストを抽出しなくてはならない。検索時にリアルタイムでテキストの抽出を行うこと(on-the-fly)も可能だが、かなり重たい処理なので、実用的ではない。このアプリケーションでは事前に、検索対象の全ての Excelファイルからテキストの抽出を行い、ファイルに出力しておき、検索はこのファイルに対して行うという方式をとる。
テキストの抽出方法について具体的な例を示しながら解説する。以下のシートには、セル、グループ化されたテキストボックス、図形(楕円)にテキストが入力されている。
[image5]

Excelファイルの操作は COMオブジェエクトを利用する

本アプリケーションは、古いタイプのExcelファイル(.xls)も対象としたいので、テキストの読み込みには Office COMオブジェエクトを使う。以下、具体的なコードに基づき解説する。
Excelアプリケーションの各要素(ファイルやシートなど)は、オブジェクトとして提供される。オブジェクトは以下のような階層を構成する。
C#プログラムで COMオブジェクトを使用するためには、ソリューションエクスプローラから以下のライブラリの参照を追加する。
シートの COMオブジェクトを取得する。オブジェクトを通してしてテキストの読み込み等の操作を行うことがっできる。

セルのテキストを読みこむ

一時ファイルを作成し、そこにSaveAsメソッドによりシートのテキストを CSV形式で書き出す。COMオブジェクトによる操作は、例えば、セルを選択する、コピーする、文字列を代入するといった Excelの UI操作を模倣する動きが多い。
前掲の Excelシートのテキストを読み込んだ結果は次の通り。複数の値を入力すると、最も左上の値のセルと、最も右下の値のセルを範囲とした表として扱われる。要素の区切りにカンマが挿入され、行ごとに改行される。空白のセルも一要素となる。例題のデータは7行 3列の表と見なされる。

図形のテキストを読み込む

図形に挿入されているテキストを読み込むには、Shapesコレクションのメンバである Shapeクラスのオブジェクを取得し TextFrame.Charactersメソッドを呼ぶ。
Shapeオブジェクには画像のようにテキストを保持できないものも含まれる。このようなオブジェクに対し上記メソッドでテキスト読み込もうとすると COMオブジェクトの中で例外が発生してしまう。これを避けるために読み込み可能なオブジェクトであるか否かを Typeプロパティの値により事前にチェックしておく必要がある。
サンプルコードでは、四角や円といったいわゆる図形とテキストボックスに対してのみテキストの読み込みを行っている。 これらがテキストを保持するのは自明だが、それ以外のオブジェクトは知らないものばかりなので、実際に Excel上で試してみて経験的に割り出すしかない。
図形はグループ化することにより任意の階層を持つことができるので、テキストを抽出する処理は再帰的なものとする。グループ化されたオブジェクは Typeプロパティにより判定することができる。

アプリケーションの解説

本アプリケーションは、下図の青枠で囲んだ部分の処理を行う。
[image8]
Excelファイルを読み込み、シートごとにテキストを抽出し、ファイル名、シート名、シートごとの図形数、ファイルの最終更新日時などとともに 下図に示した XML形式のレコードを作成しファイルに書き出す。
先に示したサンプルの Excelシートを解析した結果は次の通り。XMLブラウザではタグがアルファベット順に表示される。キーワードによる全文検索は XMLレコードの textタグに設定された文字列「はんぺんちくわぶ がんもどき...」に対して行う。
[image4]

アプリケーションの使用方法

対象となるExcelファイルを格納したフォルダ、抽出結果の XMLファイルを出力するフォルダを指定し、実行する。「All Reset」を指定すると既存のXMLファイルを全て削除する。指定しないとファイルの最終更新日時にもとづき差分更新を行う。中止ボタンにより処理をキャンセルすることができる。
[image1]
実行結果の表示。この処理では 2147本のExcelファイルを処理し、処理時間は約45分であった。
[image6]

ソースコード

Form1.cs UIコントロール
DataManager.cs テキスト抽出処理
DataManager2.cs テキスト抽出処理(partial class)
ComObject.cs COMオブジェクトラッパー
OfficeInfo.cs XMLレコード定義
Logger.cs ログ出力

COMオブジェクトの解放について

COMオブジェクトは、ガーベージコレクタに対応していないので、自前でメモリを解放しないといけない。COMオブジェクトは Excelファイルやシートを開いた数分だけ作成されるので、解放を忘れると影響が大きい。
後処理を確実に行うために COMオブジェクトをラップした IDisposableインターフェイスに準拠したクラスを作成し、Disposeメソッドを実装する。オブジェクトが Workbookであれば、オープンした Excelファイルをクローズする。アプリケーションであれば終了する。全てのオブジェクトは、ReleaseComObjectメソッドによりメモリを解放する。
一連の処理に必要な COMオブジェクトの生成を usingステートメントの中で行うことにより COMオブジェクトの解放を確実に行うことができる。

【注意事項】

この処理では、Excelファイルの読み込みのみを行うが、その際にもファイルの「アクセス日時」は更新されるので留意されたい。

MS Wordファイルのテキスト抽出について

Wordの COMオブジェクトの使用方法は、メソッドの名前や仕様といったところまで Excelと同じである。Wordのテキスト抽出についても本アプリケーションの処理方式で基本的には問題なく動作するのだが、条件によってCOMオブジェクトの中でエラーが発生する。信頼性に欠けるので本アプリケーションでは実装していない。
おそらく処理量の問題だと思うが、千本を超えるWordファイルに対してテキスト抽出を行うと、後半のどこかの時点から COMオブジェクト内で例外の発生がみられる。ビジーな状態になると発生するのだろうか。なおそこからやり直せば処理は完了する。
発生する例外の種類
●リモート プロシージャ コールに失敗しました。(HRESULT からの例外:0x800706BE)
●RPC サーバを利用できません。(HRESULT からの例外:0x0x800706BA)