MAGAZINE
ルーターマガジン
画像やPDFの表抽出で文字順が崩れる縦書きヘッダーをソート比較で特定する方法
はじめに
今回は、表内にある縦書きの項目名(ヘッダー)から正しく目的の列を特定したいときに使えるシンプルな方法を紹介します。生成AIや自然言語処理を使わないので、項目名が静的である場合に高速且つ低コストに処理できるベストとなります。
なお、本記事で使用している言語はRubyですが、他言語でも同様のロジックで実装が可能です。
課題:ヘッダー内の縦書きテキストを読み取る際に文字順が崩れてしまう
ルーターの業務では、表から特定のデータを抽出したいといった状況が数多く存在します。例えば、次のような表があったとします。
▼サンプル表

この表のヘッダー配列から「合計」が何列目にあるかを知りたい場合、以下のように文字列が完全一致しているかどうかを判定することで列番号(インデックス)が取得できます。
index = target_header.find_index { |cell| cell == '合計' }
p index
# 結果: 4
横書きのヘッダーであれば、この処理で問題なく列を特定することができます。
ですが、ヘッダーが縦書きの場合に同様の処理を使って列番号を取り出そうとすると失敗してしまいます。実際に「英語(リスニング)」の列番号を取得しようとすると、以下のように該当する列が存在しないという結果になります。
index = target_header.find_index { |cell| cell == '英語(リスニング)' }
p index
# 結果: nil
このようになる原因は、データ読み込みの際に縦書きテキストの位置関係が正しく認識されず、文字の並び順が崩れて取得されてしまうためです。
実際に読み取られたヘッダーの配列を見てみると、縦書き部分の文字列の順番がバラバラになっていることがわかります。 (表データからヘッダーを取り出す方法に関しては弊社ブログにて詳しく解説していますので是非ご覧ください)
target_header = ["出席番号", "氏名", "(リーデ英ィ語ング)", "(リス英ニ語ング)", "合計"]
生成AIや辞書を用いた自然言語処理を活用し、崩れた文字列を元の単語へ復元・補正する処理を組むことも不可能ではありません。しかし、外部モデルの導入や解析コストがかかり、処理や実装が大掛かりになってしまいます。
ですが、今回の「目的の列が何番目かを特定する」という用途だけであれば、そうした高度で難しいロジックを組む必要はありません。もっとシンプルで確実な方法があります。
解決方法:文字列を1文字ずつ分解・ソートして比較する
そこで、比較する双方の文字列を1文字ずつ分解してソートし、文字の並び順を一律に揃えた状態で比較を行います。 文字順が崩れてしまっていても、その部分に含まれている文字の集合自体は同じであるところがポイントです。
index = target_header.find_index do |cell|
cell.split('').sort == '英語(リスニング)'.split('').sort
end
p index
# 結果: 3
これにより、ヘッダー読み取り時に文字順が崩れていても問題なく目的の列を特定することができました。
注意点として、nameとmeanのように、使われている文字の構成がまったく同じである文字列がヘッダー内に存在する場合、ソートすると同じ文字列として判定されてしまいます。
アナグラムが存在するような短い単語や英数字を扱う場合は注意が必要です。
まとめ
Excelなどの構造化データとは異なり、PDFや画像からデータを抽出する現場では、縦書きテキストの位置関係が正しく認識されず文字順がバラバラになってしまうケースがたびたび起こります。
ですが、比較する双方の文字列をあらかじめ1文字ずつ分解して並び替えておくことで、特殊な仕組みを使わずとも目的の列をほぼ正しく特定できます。縦書きヘッダーの扱いでお困りの際は、ぜひこのアプローチを試してみてください。
ルーターではPDFをはじめとするさまざまな非構造化データの収集・抽出・活用を行った事例がございます。お困りの際は、ぜひご相談ください。
CONTACT
お問い合わせ・ご依頼はこちらから