表記に対して、読みがなだけあって音声表記がないときに何とかする

タイトルのような状況を、主に音声関係の人のツイートで見かける。
読みがな・音声表記の変換は、"ou"->"o:"のような単純な処理をすると、「子牛」が「コーシ」になってしまったりして悲しいことになる。
そこで、自分は音声関係ではないのだが、PerlMeCab でなんとかする方法を考えてみた。

perl -CSD -Mutf8 -F/\\t/ -nale 'BEGIN{$max=20;}@results=`echo $F[0] | mecab -N$max`;$processed=$simple=$no_daku=$F[1]; @yomi=@pron=();$i=0; $unknown_flag=0; $is_ok=0; $a_dan="[アカサタナハマヤラワガザダバパァャ]";$i_dan="[イキシチニヒミリギジヂビピィ]";$u_dan="[ウクスツヌフムユルグズヅブプゥュ]";$e_dan="[エケセテネヘメレゲゼデベペェ";$o_dan="[オコソトノホモヨロヲゴゾドボポォョ]"; if ($simple!~s/((?<=${a_dan})ア|(?<=${i_dan})イ|(?<=${u_dan})ウ|(?<=${e_dan})エ|(?<=${o_dan})[ウオ])/ー/g) { $is_ok=1; } else { for (@results) {chop;++$i,next if /^EOS/; /\*,\*$/?(/(^\p{Katakana}+)/ or $unknown_flag=1):/([^,]+),([^,]+)$/; next if $unknown_flag; $yomi[$i].=$1;$pron[$i].=$2||$1;} map{tr/ガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポ/カキクケコサシスセソタチツテトハヒフヘホハヒフヘホ/}@yomi,@pron,$no_daku;$matched_pron=""; for $i(0..$max) { if ($no_daku eq $yomi[$i]) { $matched_pron=$pron[$i]; last;}} if ($matched_pron) { for $i(1..length($processed)) { substr($processed,$i,1,"ー") if substr($matched_pron,$i,1) eq "ー";} } } $processed=~tr/ヂヅヲ/ジズオ/; $simple=~tr/ヂヅヲ/ジズオ/; $processed=~s/(?<=$a_dan)ァ|(?<=$i_dan)ィ|(?<=$u_dan)ゥ|(?<=$e_dan)ェ|(?<=$o_dan)ォ/ー/g; print "$F[0]\t$F[1]\t".(($is_ok || $matched_pron) ? $processed:"-".$simple);' < input.txt

input.txt には次のような内容を用意。

夫婦茶碗        メオトヂャワン
塩豆腐  シオドウフ
21世紀    ニジュウイッセイキ
テザリング機能  テザリングキノウ
待宵草  マツヨイグサ
文科省  モンカショウ
子牛    コウシ
中央揃え        チュウオウゾロエ
大江戸線        オオエドセン

出力は、次のようになる。

夫婦茶碗        メオトヂャワン  メオトジャワン
塩豆腐  シオドウフ      シオドーフ
21世紀  ニジュウイッセイキ      -ニジューイッセイキ
テザリング機能  テザリングキノウ        テザリングキノー
待宵草  マツヨイグサ    マツヨイグサ
文科省  モンカショウ    モンカショー
子牛    コウシ  コウシ
中央揃え        チュウオウゾロエ        チューオーゾロエ
大江戸線        オオエドセン    オーエドセン

3列目が "-" になっているものは単純な変換なのでチェックが必要。

仕組みは、次の通り。
まず、長音の可能性が(「ネエ」「コウ」など)がなければ、次のブロックを飛ばす。

表記を MeCab に渡し、20-best (数は適当)で解析結果を受け取る。
その中で、読みがなが元ファイルの読みがなと一致するものを探す。
この時、濁点は無視して比較する。
MeCab は連濁処理に弱いところがあり、例えば「中央揃え」の N-best をどこまで取っても「チュウオウゾロエ」は見つからないからだ。
一致するものがあれば、それに対応する発音表記を取得。
しかし、これはそのままでは使えない。
「チュウオウソロエ」に対応する発音表記は、もちろん「チューオーソロエ」であり、望む「チューオーゾロエ」にはなってくれないからだ。

そこで、元の読みをベースにする。
そもそも、音声表記への変換で一番の難所は長音(ー)だ。
元の読みの中で、取得した発音表記が「ー」になっている位置の文字を、同じく「ー」で置き換える。

元の読みの「ヂ」「ヅ」「ヲ」はそのまま残っているので、それを単純置換で「ジ」「ズ」「オ」にする。
「カァ」→「カー」などの置換を行う。
以上。

「21世紀」のように数字が入っているものは、MeCab で読めないので仕方がない。
「待宵草」は、「待:マツ」のペアが入っていないので、本来MeCabでは読めないところだが、長音の可能性がないのでそのまま出している。

失敗するものは多くないと思う。
いろいろテストした。

可読性の非常に悪いワンライナーだが、使い所はあると思うので、よかったら使ってみていただければと。

(追記1)実際はこんなに簡単な話ではないようだ。恥ずかしいけど自戒をこめてこのままにしておく。
(追記2)長音の可能性がなければ処理を飛ばすようにした。
(追記3)変換に失敗にした時、単純な置換にフォールバックするようにした。