問題が発生する環境・条件* 0.22.2 に、[日本語パッチ]を適用した環境 * ある種のメール(複数の文字コードが混在したメールだと考えていたのだがそれだけが条件というわけではないらしい)を処理した場合に、Text::Kakasi による分かち書きを行った際に文字化けが生じる。 問題の詳細* Text::Kakasi の辞書を閉じない(パラメータを再設定しない)状態で、Encode モジュールで複数の文字コード間の変換を行うと、Text::Kakasi::do_kakasi で文字化けが発生する。 * Text::Kakasi 2.x では、内部で Encode モジュールを使うようになっており、この影響ではないかと考えられるが、詳しい原因については不明。 試したこと* [Text::Kakasi のドキュメント]によれば、「$Text::Kakasi::HAS_ENCODE を 0 にする」ことによって Encode 関係の機能を無効にできるということだが、設定してみても効果はなかった。 問題の解決策(暫定)* Text::Kakasi の処理の度に、パラメータを再設定することによって回避可能だが、パラメータを再設定するだけでは辞書ファイルが何度も開かれてしまって「Too many open files」エラーが発生。 * 辞書を毎回開いて閉じるようにすることによりすべての問題が解決するが、パフォーマンスが悪くなる。 * 文字コードが変わった時点で Kakasi の辞書をいったん閉じて開くようにすると、問題が起こっていたメールについては解決された。が、これですべてが解決されたかどうかは不明。 問題検証のためのプログラムスクリプトと同じディレクトリに、shiftjis、7bit-jis の混在したテキストファイル [test.txt] があるという条件で検証。 コメントアウトしてある行を元に戻すことにより、問題が発生しなくなることを確認。 <pre>#!/usr/bin/perl use strict; use Encode; use Encode::Guess; use Text::Kakasi; my %encoding_candidates = ( 'Nihongo' => [ 'shiftjis', 'euc-jp', '7bit-jis' ] ); # $Text::Kakasi::HAS_ENCODE = 0; # パラメータを設定して辞書を開く Text::Kakasi::getopt_argv("kakasi", "-w -ieuc -oeuc"); |
解決しました |
kakasi_test(); |
: この問題は解決し、パッチの内容は POPFile 0.22.3 へ取り込まれました。 |
# 辞書を閉じる Text::Kakasi::close_kanwadict(); sub kakasi_test { my $line; open(DB, "./test.txt"); while (<DB>) { $line = $_; # 文字コードを euc-jp に変換する $line = convert_encoding( $line, '7bitjis', 'euc-jp', '7bitjis', @{$encoding_candidates{'Nihongo'}} ); print $line; # 分かち書きを行う $line = Text::Kakasi::do_kakasi($line); print $line; } close(DB); } # 文字コードの変換 sub convert_encoding { my ( $string, $from, $to, $default, @candidates ) = @_; require Encode; require Encode::Guess; # First, guess the encoding. my $enc = Encode::Guess::guess_encoding( $string, @candidates ); if(ref $enc){ $from= $enc->name; print "Guessed encoding : $from\n"; } else { |
問題が発生する環境・条件 |
# If guess does not work, check whether $from is valid. |
* 0.22.2 に、[日本語パッチ]を適用した環境 * ある種のメールを処理した場合に、Text::Kakasi による分かち書きを行った際に文字化けが生じる(他にも原因があるのかどうかについては不明)。 |
if (!(Encode::resolve_alias($from))) { |
問題の原因 |
# Use $default as $from when $from is invalid. |
* Kakasi の漢字コード自動判定には問題があり、正しい漢字コードを Text::Kakasi に伝える必要があった。 |
$from = $default; } } |
問題の解決策 |
# 以下のコメント部分を元に戻すことにより、テスト用ファイルにおける問題は解消される # if ( $from ne 'ascii' && $last_encoding ne $from ) { # $last_encoding = $from; # # close_kakasi(); # init_kakasi(); # } |
* 漢字コードを Text::Kakasi にちゃんと伝える。具体的には、Text::Kakasi::getopt_argv("kakasi", "-w -ieuc -oeuc"); としていた部分を、Text::Kakasi::getopt_argv("kakasi", "-w", "-ieuc", "-oeuc"); と修正した。 |
unless ($from eq $to) { my ($orig_string) = $string; |
関連情報 |
# Workaround for Encode::Unicode error bug. eval { Encode::from_to($string, $from, $to); }; $string = $orig_string if ($@); } return $string; }</pre> |
* [POPFile 全般 - 0.22.2 用日本語パッチ(試験公開)の動作テストをしていただける方募集] |