■ テキストファイルの見出し解析アルゴリズム


■ 見出し解析が出来れば…

 パソコンの狭い画面では長いテキストは読みにくい、と思っている人は少なからずいるようです。実際ドキュメントなどで印刷を前提に書かれているものがかなりあります。
 でもパソコンでそのまま読めれば印刷の手間も省けますし、検索などパソコンのほうが有利な面も多いです。実際 BBSのログファイルのような定形テキストを読むものなら結構強力なものもあります。

 でもヘッダが自動生成される通信ログならともかく、ドキュメントの場合決められた形に書くのは大変だし抵抗もあるのか、専用ぺージャーを使った専用書式がいくつか提唱されたものの広まりませんでした。

 最近では大メーカーの力で無理矢理? HELPやHTML形式のドキュメントが増えてきましたが、やっぱし書くのは大変のようです、手間もそうですが、例えばWinHELPの場合フリーのコンパイラは無いようで、金銭的な問題もあります。
 その分、読み手側が読みやすくなることが保証されているのならまだ構いません。しかし読み手の側にも他の環境で読むのに不便だったり、ブラウザは起動に時間がかかったり、マウス操作が苦手な人にはかえって読みにくくなる場合がある等の問題があります。プレーンテキストに対するデメリットは少なくありません。望ましい方向に向かっているとは言えないと思うのです。

 むしろ逆に、書き手は書きたいように書いて、読み手は読みたい形にして読む。そんなツールが必要ではないかと思います。不定形のテキストをリアルタイムで解析して見出しを抽出し、一覧、ジャンプ等が出来るぺージャー…
 出来ないことではありません。一見思い思いの書式で書かれたテキストもよく見るとそれなりの法則性をもっているものですから。

 実はこの手のツールは探せば結構あったりします。でもどれもメジャーにはなれなかったようですし、使ってみると解析力が物足りない印象を受けます。
 しかしメジャーな分野でないだけに、アルゴリズムの改良の余地は残っていると思います。JPEGのように、昔は実用にならなかったアルゴリズムがマシンパワーの向上で使えるようになっているかも知れないですし。


■ 見出しの種類

 さて、実際のドキュメントなどで使われている見出しですが、それほど種類は多くありません。いや、全部数えれば相当な数になると思いますが、使用頻度の高いパターンはかなり限られるのです。

 まず多いのは、行頭に■、●、☆等の全角記号か、数字が来るパターンで、以前にPerlで解析ルーチンを作って調べたときは、おそらく6〜7割はこのどちらかだったと思います。ただ数字には全角、算用数字/漢数字、括弧の有無、ピリオドやハイフンが付いたもの(1.や2-1)、第n章…等、それなりに種類があるのですが。

 あとは、見出しが括弧で囲まれているもの(<〜>や、[〜]、【〜】)や、大規模なソフトの長文ドキュメントに多い複数行の見出し(=======…で見出しが囲まれている等)。英文字+ピリオド(a.)、行末にコロン、DOSソフトのコマンドラインオプション(-か/で始まって、次が英数字)や、キー役割の説明([RETURN]や[A]のように[〜]で囲まれていることが多い)のような小さな区切りもあります。

 他にもいろいろあるわけですが、解析可能な種類を増やしていけばスピードも落ちますし、誤解析も増えます。全てをサポートしようとせず、目的によってバランスを考えて上手く妥協することが必要になるでしょう。一度変換すればよいコンバーターなら解析精度のほうが重要ですし、ファイラーの内蔵ぺージャーとして日常的に使うならスピードが大切です。


■ 誤解析対策

 と言うわけで、見出しを抽出するだけなら別に難しくはないのです(正規表現の使えない言語だと面倒ではあるかも知れませんが)。難しいのは見出しでないものまで見出しとして誤解析してしまうのを防ぐことです。
 誤解析でおそらく一番多いのは、箇条書きにされている部分を見出し扱いしてしまう場合です。これは後述します。

 次は本文中に偶然紛らわしい記号などが入っている場合で、特に半角数字等は偶然行頭に来ることも多いです。
 対策としては見出しと認識する基準そのものを厳しくするのと、前後関係を見ることが挙げられます。

 前者は、数字が1桁の場合はほとんどが次にピリオドが来ますので、そうでないのは捨てたり、またピリオドなどの次がスペースかどうかをチェックしたり、数字が多すぎる場合捨てたり(いくら大きなドキュメントでも第100章とか言うことはないでしょう)です。
 ただし厳しくし過ぎると逆に見出しを見落とす場合もあるので難しいところです。半角数字の場合も行頭からスペースを入れずに書かれているもののみ拾うようにすれば誤解析率は格段に下がる代わりに、時々見出しを見落とします。


 後者は例えば、前後の行、特に前行が空行なら見出しである確率が高いというのは結構有効な判断基準です。大きな見出しの場合は前前行まで空行なこともあります。
 また数字系の見出しなら、数字が順番に出てこなければ誤解析を疑っていいでしょう。テキスト全体を通して1つだけしかなかったという場合もおそらく誤解析だと思います(複数の項目が無いと数字は使わないはずですから)。

 こういう多数の条件を判断する場合は、判定用のパラメーターに、ある条件を満たせば+1、またある条件を満たせば-2…のように加えていき、最終的にいくらになったかで判断するのがいいと思います。
 (ちなみにドラクエのAIバトルで似たようなことをやっているとか(^^;)


◆ 箇条書チェック

 文中で箇条書きを使うかどうかは個人差がありますが、ソフトのドキュメントには比較的多いように思います。その場合先頭は大抵「・」ですが、意外と◎や☆等の、一見見出し記号のようなものも多いのです。これを見出しとして解析してしまうと見出し一覧が細かく区切られ過ぎて見通しが悪くなります。
 また逆に「・」の場合でも、もしくは筆者が箇条書き的な意味合いで書いたものでも、各項目がそれなりの長さを持っている場合は見出しとして認識したほうがいいでしょう。
 つまり、問題なのはそれらがでてくる間隔で、同種の見出しが短い間隔で連続して出てくる場合は、見出しと見なさない処理が必要になるわけです。
 その場合、同種の見出しが連続する区間の平均行数を取って、それがある程度以下なら切り捨てるようにしたほうがいいと思います。と言うのも、例えば1個目から2個目の間隔が2行、2個目から3個目までが10行、3個目から4個目が3行〜のように、間隔が広がったり詰まったりすることも多く、詰まっている部分だけ認識しないようにすると、一覧と本文のバランスが悪くなるので。

☆ 箇条書きチェックの落とし穴

 平均の取り方にも落とし穴があります。箇条書き区間というのは終了後すぐに次の見出し記号が出てこず、そのまま本文に戻ることが多いのです。どこまでが最終項目でどこからが本文かを把握しないと、本文の長さが最終項目の長さに加算されてその結果平均値が跳ね上がることがあるわけです。
 対策としては本文と最終項目を見分けるアルゴリズムを考えるのが本当でしょうが、最終項目を含めた平均行数が最終項目を除いた平均の何倍にもなっている場合、後者のほうを判断材料にすることだけでも結構どうにかなります(^^;。

 あと、印刷を前提としたテキストの場合、ページのすき間に相当量の空行が入りますので、計算のときには省かないと駄目です。その場合大抵プリンタのページ送りコード(^L)や、ページ数らしきものがありますし、付近に「*** User's Manual」等の文字があることが多いので、その辺りで判別してください。

 また、複数の見出し記号が狭い区間に交互に出て来ることもあります。一番多いケースは筆者側で目次を書き込んでいる場合です。これも対策の必要があります。


■ 階層解析

 ある程度長いテキストになると、大抵見出しも単一階層ではなく、大見出しの中に中見出しがあり、さらにその中に小見出しが…と言う風になっているものです。
 そういう場合、一番大きな見出しだけ表示したり、全ての見出しを表示したり、何通りかに表示を切り替える機能があったほうがいいでしょう。そうなると、どの見出しが何階層目なのかも解析する必要が出てきます。

 ちなみにこれは誤解析を防ぐアルゴリズムとも重なってきます。大きな見出しほど判りやすい形をしていることが多く、誤解析は少ないからです。
 とりあえず解析のキーとして使えるものを挙げてみると…

◆ 順番

 大見出しの中に中見出し〜の形だとすれば、最初に出くわすのが一番大きい見出し、次が2階層目…となっているはずです。実際はそうなってないことも多いのですが、半数くらいのテキストはそれで大丈夫なようです。

◆ 種類

 複数行見出しや、「■」「□」等は大きな見出しとして使われることが多く、「・」やコマンドラインオプション等は小さな見出しのことが多いです。
 また数字の見出しなら例えば1階層目が「1.」、その次が「1.1.」「1-1.」のようになっていることが多く、判別できます。また全角数字と半角数字がある場合は、全角のほうが大見出しである確率が高いでしょう。

◆ スペースの数

 大見出しは行頭から、それより小さい見出しは行頭にスペースを入れて字下げというパターンは案外多いです。同一の記号をスペースの数だけ変えて違う階層の見出しに使っている例さえあります。
 ただし、逆にスペースの数がある程度より多い場合、センタリングされている場合があります。スペースが多かったらその行の長さに行頭スペースの数を足して、80前後ならそう判断していいでしょう。
 こういう場合は逆に、スペースの数が少ない見出しよりも大きな見出しである確率が高いわけです。


■ 階層最適化

 通常、同一の見出し記号は同階層と見なしますが、行頭スペースの数が違えば同一記号でも違う階層と判断したほうがいいようです(前述のセンタリング時除く)。
 ちなみに全角スペースと半角スペース*2は同一視したほうがいいです。と言うのも、稀に同階層の見出しなのに、片方は全角1、もう片方は半角*2になっている場合があるのです。おそらく意図的なものでなく、多くのエディタで見掛け上区別が付かないため、いつの間にかそうなってしまったものと思いますが。

 一見違う階層に見えてしまうと言えば、数字見出しで見出しの幅を揃えるため、1〜9章は全角で、10章以降は半角で書いているのがあります(めったにありませんが)。


 ところで逆に、違う見出しが同階層に割り当てられる事というのもあります。特に中程度の長さのドキュメントで、一番大きな見出しの記号は統一しても、それ以下は書いたときの気分で変えてしまっているのではないかと思えるのが結構あるのです。確かにこういう解析をするならいざ知らず、普通のぺージャーで見れば別に困るものではないですからね。

 このあたりの解析アルゴリズムは、まだまだ試行錯誤中ではあります。


■ P.S.

 アルゴリズムの使い回し?などは歓迎します。使い物になるかどうかは保証しませんが。この種のソフトがたくさん出てきたり、ファイラーに内蔵されるようになったら面白いですけどね。


 設置:98/7/19  最終修正:98/7/19

【戻る】