ひまつぶし雑記帖

小ネタ:pdftotextで文字データを抽出

2024/8/28 [15:40:57] (水) 天気

元データがPDFで、圏点(傍点)やダッシュをPDFから検出する必要にせまられた。
目視確認などありえないんで、テキストデータとして取り出して検索しよう、というのが今回のエントリ…というかエントリにするまでもない内容なんだけど、たぶんそのうち忘れるんで、メモ。

PDFから文字情報だけをひっぱりだすのに定番の「pdftotext」というツールを使う。
perlだけでもできそうなんだけど(PDF::API2あたり)ちょっと時間も押してるんで、外部ツールを間に挟むことにした。

まずは肝腎のpdftotextのインストール。これがpoppler-utilsというパッケージだなんて検索しないとわからなかった(pdftotextというパッケージがあるもんだと思ってた)

以下のコマンドラインでインストール

sudo apt-get install poppler-utils

unix系のツールの例に漏れず、これもいろんなオプションが用意されてるけど、今回必要なのは文字情報だけ。レイアウトデザイン情報やなんかは不要。
rawオプションをつけて利用する。
image
たとえば「kappa.pdf」の文字情報を抜き出すのは

pdftotext -raw kappa.pdf

こうすると「kappa.txt」に文字情報を吐き出す。ただ、これだとひと文字ずつだあーっと出力されるので、ここからがテキストデータを扱わせたら最強のperlの出番。image 
pdftotextの出力には改ページがつくので、そこで改行すれば「それっぽい段落」ごとに見えるひとに優しいテキストファイルとなる。

open(P, '-|', 'pdftotext -raw kappa.pdf - ' ) || die;
binmode STDOUT => ":utf8";
open(OUT, '>' , 'kappa.txt') || die;
binmode OUT => ":utf8";
while(<P>){
    my $line = Encode::decode('utf8', $_);
    $line =~ s!\r?\n!!;
    $line =~ s!\x{C}!\n!;
    print OUT $line;
}
close(OUT);
close(P);


特筆すべきようなスクリプトじゃないんだけど。
perlは外部コマンドの「標準出力」をパイプで受け取って加工整形できる。

open(P, '-|', 'pdftotext -raw kappa.pdf - ' ) 

openの
・第2引数で、標準出力を受け取りますよ、という指定
・第3引数はpdftotextの結果を標準出力に出すからね、という指定
これだけでそれっぽい段落にわけたテキストファイルを作ってくれる。

そうしたら、あとは出力されたテキストファイルからダッシュや圏点(傍点)っぽいものをperlで検知するだけ。imageこれはワードで作ったPDFで「、」が圏点となっている。inDesignで作られたデータだと「0」(ゴマ)「4」(ドット)となる。

直接触ってもいいんだけど、一度テキストファイルに吐き出したほうがなにかわからないことが起こった時に便利なので、こういう仕様、段取り。

このスクリプトのおかげで抜け漏れは捕捉できるんでずいぶんラクになった。

以前、目視確認とか無駄なだけだし、んなもんツール作ってやればいいじゃん、とか言ったら、そしたら仕事がなくなる、目視確認手作業修正は必須だ、と言われて心底、呆れた。
カネをもらった上で、人間の作業=ミスが入り込む原因になる工程を入れるって、いろいろ悪質すぎる。
ITといってもピンキリで、こんなのが入り込んでるから要注意。
そもそも、その程度の仕事なんて、なくなっても問題ないし、特に困らない。

»電子書籍制作代行についてはこちら

電子書籍でエラーになる絵文字の検知

2024/8/24 [17:10:50] (土) 天気

今回のエントリは。
経緯
・電子書籍でエラーになるのが絵文字だった。
・元データから絵文字を検知する必要が出てきた。
結論
・perlを使えば絵文字のチェックも簡単だった。

てことなんだけど、調べてみたらunicodeまわりが魔窟でびっくり。またハマりそうなのでメモ。
以下は、何を今さらという話が無駄に長くて、既知のかたには役に立たない内容です。


電子書籍に求められる基準はほぼ以下のふたつ
・Epubcheckでエラーはない。
・kindle previewerでエラーはない。

epubcheckでエラーがなければEPUB3の電子書籍として問題はないし、kindle perviewerでエラーをチェックするのは最大の配信サイトであるAmazonでエラーがあったら商売上よろしくないから。

上記2つのチェックをクリアしたのに、一部の配信サイトでエラーになるという指摘があって、追いかけてみると、問題になったのが「絵文字」
「😀」←こういうやつ

原稿に絵文字があったんで、あれ?これってイケるんだっけと思って作ってみて、上記2つのチェックにかけてもエラーはなかった。
文字コードがShiftJISの時代ならともかく、今どきはutf8。
utf8のおかげで文字化けなんかを気にする必要はほぼなくなった。機種依存、環境依存文字に神経質にならなくていいのはストレスフリーで、いい時代になったもんだとのんきに感慨深い今日この頃だったのに…。

文字として問題はないんだけど、配信サイトごとにビューワーが違ってたりして、そのビューワーが絵文字に対応してるかどうかのことだと思う。

「EPUB | CSS組版ブログ」
https://blog.antenna.co.jp/CSSPage2/archives/category/epub

↑絵文字なんかについて、縦書きのepub3が始まった頃に議論があったらしい。
(電子書籍元年当時の話が読めるのでオススメ)

「横倒しのまま」にするのか「正立させる」のか。文字の意味的に方向があるものは正立させる?とか。そのあたりのすり合わせが問題になってたっぽい(という理解でいいのかなあ)

これは縦書きの場合、見た目けっこう致命的なので、たぶん、絵文字の対応を見送ったビューワー=配信サイトがあったんじゃないかと思う(憶測)
あるいは、そもそも、絵文字は環境ごとで見え方も違うのでそこが問題なのかもしれない(憶測)
そんなこんなの名残りもあって、面倒なものは却下、ということで今でもエラーにする配信サイトがある、んだろう(めっちゃ憶測)

epubcheckでもkindle previewerでもエラーにならない文字を自前で検知する必要にせまられる事態となった。
電子書籍のボリュームを目で追ってその中から絵文字を見つける、目視で探すなどありえない。必ず漏れが出る。

なもんで、絵文字の文字コードを調べてみて改めて今さらびっくりのunicodeだ。

ちなみに、文字を表示させるためには、以下の2本立てになっている。
・unicodeの文字コード表で文字を指定特定していて
・文字コードをエンコードすることで文字を表現する
これ、けっこう勘違いするんだけど、utf8というのは文字コードではなくてunicodeの文字コードをエンコードする方法の名前のこと。

以下のサイトを読んでまたびっくりすることをおすすめする。
「文字コード再入門 ─ Unicodeでのサロゲートペア、結合文字、正規化、書記素クラスタを理解しよう!」
https://en-ambi.com/itcontents/entry/2020/04/28/103000/
「書記素クラスタ - daiizfeel 2022」
https://isobe-yaki.hateblo.jp/entry/2023/07/20/194803

てのはともかく、読んでも難しいんで、なにか大変なことになってるんだなあ、でOK。

そもそもutf8でエンコードされた、日本語などは、ひと文字を表すのに、そのコードは3バイト使う。
ひとつの文字がアルファベットのように1バイトではないので
たとえば「日本語の文字」の6文字は、1つの文字に3バイトのコードが必要で、文字列の長さをバイト数でいうと18となる。

文字数いくつだっけ?て時に、バイト数の18ではなくて「正しく」6と数えるためにエンコードされている必要がある。

unicodeのコードをエンコードして初めて「文字として認識される」
このエンコードする方法がutf16だったりutf8とか呼ばれて、エンコードすることで初めて「文字として認識された文字を表示する=扱うことができる」という変な日本語。

perlの場合、utf8フラグというのを使うことで問題解決する。

my $str = '日本語の文字'
my $utf8 = Encode::decode('utf8',$str)
print length($str)
→18文字 
print length($utf8)
→6文字


perlはこのおかげで、文字の扱いについて、普段はまずほとんど、こんな面倒くさいことを意識する必要はなくて、なもんで、すっかりわけがわからず混乱してしまったのが昨日今日の話、だ(とほほ

unicodeとutf8についてのおさらいができたところで、やっと本題。
じゃあ、絵文字を検知するには絵文字が使ってるコードを見つければいいだけじゃん。簡単だろ、と思ったらまたひと悶着。

ていうか、ここからが今回の本丸、一丁目一番地(死語)
utf8フラグだけでは解決しない「結合文字」というのがあった。

「1つの文字を表示しているのは、1つのunicodeのコードポイント」とは限らない。
ひとつの文字を表示、扱うのに、複数のunicodeのコードポイントを使ってるケースがあって、見た目のひと文字とそれを表すコードは1対1ではない、ということ。

perlでutf8フラグがついていてもutf8の文字コード(←unicodeコード表によるコードではなくてエンコード後の文字コード)2つ結合した文字はlength()では意図通りに取得できない。ひと文字として扱ってほしいのに、たとえば二文字としてカウントされてしまってお手上げ。

実のところ、書記素クラスタというのはこういう結合文字も含めた呼び方で、書記素クラスタに対応すれば「結合文字」も「ひと文字」として扱うことができる。書記素クラスタというのがなんだか「とても面倒くさい」というのはこのあたり。

こうなってくると、電子書籍でエラーをなくすために、なんでこんなことまで調べにゃならんのか。そもそもレアケースだし、配信サイト個別のクレーム対応でいいんじゃないのか。と思わないでもないけど。乗りかかった船だししょうがない。

話がそれた。
perlはこれも解決してくれる。て、テキストを扱わせたらperl最強じゃね?

「絵文字を含む文字列を分割~解説編~」
https://www.lemorin.jp/perl/3b_split_char.html
↑こちらのサイトに知りたいことのすべてがあった(多謝

 my $line = Encode::decode('utf8', $_);
    my $len = length($line);
    print $len . "\n";
    my @x = $line =~ m!\X!g;
    print scalar(@x) . "\n";


length()では「見た目のひと文字」じゃなくて困ってたところ、perlでは「いい感じに」「ちゃんと」文字として認識できる文字のための正規表現「\X」が用意されてた。

「perlの正規表現」
https://perldoc.perl.org/perlrebackslash#Misc

ということで、やっと本エントリの締めとなります(長っ!
問題のない文字ダネを削除して残った文字を正規表現「\X」で配列に取り出して、「見た目のひと文字」をコードポイントにバラして16進表現して絵文字のコードに検索をかける。検索がヒットしたら、それはイコール絵文字。

「HTMLの絵文字 文字コード表」
https://gray-code.com/html_css/list-of-emoji/
↑絵文字のコードはこちらの一覧から拝借しました。
こちらで掲載されているコードを絵文字判定の対象としました。

これでやっと絵文字検知。
前から言ってるんだけど、人間の目視確認、手作業修正(目grep、手marge)なんて1mmも信用できない。特におれ。なので機械に頼めるなら機械に任せるのが正解。

↓こちらも参考になりました
「Perl 5.26 & Unicode 9.0 で変わる書記素クラスタ(grapheme cluster)のお話」
https://shogo82148.github.io/blog/2017/08/25/unicode9-grapheme-cluster/

「UTF-8の文字コード表」
https://orange-factory.com/dnf/utf-8.htmlimage
本エントリとはまったく関係ないけど。

この埼玉県八潮市の資料館はびっくりの充実。行く前は小学校の教室ぐらいなもんだろ、と思っててすみませんでした。
交通アクセスにちょっと難があって、気楽にとはいえないけど、行けるかたはぜひぜひ
https://www.city.yashio.lg.jp/kurashi/shisetsuguide/shiryokan/index.html

[08/25 16:58:54] いろいろ間違えてたので改稿
「文字につかうバイト数」と「コードポイント」を混用していた、という乱暴な理解だった(恥

»電子書籍制作代行についてはこちら

profile

profile

 
doncha.net
contact:
»運営者
@t2aki@tokoroten.doncha.net

ため池

[2024/09/13 13:23]
光瀬龍の原案を横田順彌がノベライズして松本零士の挿絵みたいな…
どこか懐かしさを感じるなあ>ケン リュウ

[2024/09/13 13:14]
『紙の動物園』ケン・リュウ 古沢嘉通
「選抜宇宙種族の本づくり習性」
#読書ドン

[2024/09/13 08:48]
哺乳類がおしりで呼吸できるのを発見 今年も日本にイグ・ノーベル賞:朝日新聞デジタル
https://www.asahi.com/articles/ASS9D3S33S9DULBH00KM.html

「人間って、口から肛門までの長い肉の筒に、脳とか余計なものがついただけの生き物ですなあ」
…という、かんべむさ ...

@t2aki@tokoroten.doncha.net

検索
<<2024/08>>
    123
45678910
11121314151617
18192021222324
25262728293031

リンク

WINDOWS版サウンドノベル
おかえりください PC WINDOWS版サウンドノベル
『おかえりください』体験版

[1 Page]

TOTAL:2988

2024 (11)
1 (2)
2 (2)
3 (1)
5 (1)
7 (2)
8 (2)
9 (1)
2023 (53)
1 (1)
2 (5)
3 (1)
4 (1)
5 (3)
6 (9)
7 (9)
8 (6)
9 (5)
10 (3)
11 (2)
12 (8)
2022 (16)
1 (1)
3 (2)
6 (2)
7 (1)
8 (4)
9 (2)
10 (1)
11 (2)
12 (1)
2021 (12)
1 (3)
2 (1)
6 (1)
8 (2)
9 (1)
10 (1)
11 (2)
12 (1)
2020 (18)
1 (2)
2 (6)
4 (1)
6 (1)
7 (2)
8 (2)
12 (4)
2019 (17)
1 (3)
2 (4)
3 (2)
4 (2)
5 (1)
6 (1)
8 (1)
10 (1)
12 (2)
2018 (21)
1 (3)
2 (2)
3 (2)
4 (1)
5 (1)
6 (6)
8 (1)
9 (1)
10 (2)
12 (2)
2017 (32)
1 (2)
2 (1)
4 (2)
5 (1)
6 (6)
7 (3)
8 (5)
9 (3)
10 (2)
11 (2)
12 (5)
2016 (41)
1 (5)
2 (5)
3 (2)
4 (3)
5 (4)
6 (6)
7 (2)
8 (2)
9 (3)
10 (1)
11 (4)
12 (4)
2015 (99)
1 (11)
2 (12)
3 (9)
4 (6)
5 (8)
6 (8)
7 (3)
8 (5)
9 (16)
10 (6)
11 (1)
12 (14)
2014 (112)
1 (16)
2 (5)
3 (6)
4 (12)
5 (16)
6 (19)
7 (9)
8 (6)
9 (4)
10 (8)
11 (6)
12 (5)
2013 (145)
1 (24)
2 (15)
3 (18)
4 (23)
5 (14)
6 (11)
7 (7)
8 (11)
9 (5)
10 (4)
11 (6)
12 (7)
2012 (103)
1 (1)
2 (1)
3 (4)
4 (3)
5 (7)
6 (26)
7 (17)
8 (5)
9 (8)
10 (10)
11 (11)
12 (10)
2011 (54)
1 (4)
3 (7)
4 (4)
5 (14)
6 (6)
7 (3)
8 (3)
9 (1)
10 (4)
11 (2)
12 (6)
2010 (70)
1 (12)
2 (7)
3 (6)
4 (6)
5 (3)
6 (10)
7 (6)
8 (4)
9 (3)
10 (4)
11 (3)
12 (6)
2009 (144)
1 (15)
2 (12)
3 (12)
4 (6)
5 (15)
6 (6)
7 (10)
8 (9)
9 (17)
10 (12)
11 (14)
12 (16)
2008 (148)
1 (10)
2 (6)
3 (10)
4 (11)
5 (13)
6 (10)
7 (13)
8 (19)
9 (18)
10 (12)
11 (13)
12 (13)
2007 (106)
1 (7)
2 (5)
3 (3)
4 (7)
5 (5)
6 (9)
7 (8)
8 (13)
9 (18)
10 (11)
11 (8)
12 (12)
2006 (158)
1 (28)
2 (28)
3 (25)
4 (7)
5 (9)
6 (7)
7 (12)
8 (13)
9 (10)
10 (7)
11 (6)
12 (6)
2005 (350)
1 (31)
2 (26)
3 (26)
4 (27)
5 (29)
6 (30)
7 (32)
8 (30)
9 (30)
10 (32)
11 (29)
12 (28)
2004 (292)
1 (24)
2 (24)
3 (29)
4 (27)
5 (28)
6 (25)
7 (26)
8 (24)
9 (12)
10 (19)
11 (26)
12 (28)
2003 (318)
1 (22)
2 (25)
3 (21)
4 (28)
5 (28)
6 (28)
7 (28)
8 (29)
9 (26)
10 (29)
11 (28)
12 (26)
2002 (317)
1 (29)
2 (26)
3 (26)
4 (25)
5 (28)
6 (30)
7 (27)
8 (21)
9 (25)
10 (27)
11 (28)
12 (25)
2001 (277)
1 (17)
2 (21)
3 (23)
4 (20)
5 (31)
6 (18)
7 (26)
8 (25)
9 (29)
10 (19)
11 (24)
12 (24)
2000 (53)
6 (9)
7 (4)
8 (2)
9 (3)
10 (1)
11 (15)
12 (19)
1999 (3)
7 (1)
10 (2)
1998 (18)
9 (9)
10 (7)
11 (2)