文字化け対応の指針
さて、日本語の文字化けにはざっと上記の3種類があります。あるものは不可避ですが、プログラマー的にはなるべく問題が起きないように努力したいところですよね。残念ながら全てを解決することはできないものの、読めなくなる問題を避けるため、いくつかの指針を設けることができます。
入力を避ける
例えば、入力されたデータを後でメールで送信することが分かっているのであれば、ISO-2022-JP に含まれない文字は入力の段階でエラーとしてしまう対応が考えられます。後で Shift_JIS (または CP932) で CSV ファイルにしたい場合も同様です。 (もちろん、メールも CSV も UTF-8 での運用もあり得ます。その場合は特定の文字の文字化けの心配は無くなります。色々な可能性を検討して下さい。)
また、CSV (Shift_JIS系文字コード) を Mac と Windows の両方で文字化けなく読めるようにしたい場合も、MacJapanese と CP932 で共通していない文字の入力を避ける必要があります。
異なる文字コード間で共通でない文字のチェック方法
どの文字が共通していないか、文字コードの仕様を調べて正規表現で制限することもできますが、面倒ですね。この場合は以下のように「一旦他の文字コードに変換して逆変換で戻した時に同じ文字列になるか」をチェックすると簡単です。
use strict;
use warnings;
use utf8;
# 文字化けを起こさないかチェックする
# 引数:文字列(内部表現)、使いたい文字コード(Perl表記)の配列参照
# 戻り値:1=OK、0=NG
sub is_safe_str{
my ($str, $encref) = @_;
#文字列が指定されていない場合はOK
defined $str and length $str or return 1;
#文字コードが指定されていない場合はOK
defined $encref and ref $encref eq 'ARRAY' and scalar @$encref or return 1;
my $roundtrip = encode($encref->[0], $str);
for (my $i=0; $i<scalar @$encref; $i++){
#順番にコード変換し、最後にUTF-8に戻す(生文字列)
from_to($roundtrip, $encref->[$i], $encref->[$i+1]||'utf8');
}
decode('utf8', $roundtrip) eq $str
and return 1
or return 0
;
}
&is_safe_str('波線~です', [qw(MacJapanese cp932 iso-2022-jp)])
and print "OK\n"
or print "NG\n"
; 変換する
よく使われる機種依存文字の中には、文字化けしない他の表現に変更できるものがあります。例えば、UTF-8で入力した「①」 (マル1、U+2460、e291a0) は CP932 に変換した時に 8740 に変換され、これはMacで見ると「(日)」になる場合があります。このような文字の場合、例えば「マル1」は「(1)」など、代替表現に変換してしまえば文字化けを避けることができます。
このような変換可能な文字は例えば、マル付数字、㈱、㈲、㎡、等があります。以下のコードで変換できます。
use strict;
use warnings;
use utf8;
# 文字化けを起こす可能性のある文字を変換する
# 引数:文字列(内部表現)
# 戻り値:文字列(内部表現)
sub conv2safe_expression{
my $str = shift;
defined $str and length $str or return $str;
#変換設定
my @expressions = map {[split(/,/, $_, 2)]}
qw(
①,(1)
②,(2)
㈱,(株)
㈲,(有)
㎡,平方メートル
); #必要なだけ足す。多い場合は外部ファイルにすると分かり易い。
for my $e (@expressions){
$str =~ s/$e->[0]/$e->[1]/g;
}
return $str;
}
print &conv2safe_expression('38.23㎡'); # 38.23平方メートル エンティティで表現する (HTMLの場合)
もはや新規 Webサイトを UTF-8 以外で作成することはないと思いますが、この方法は、Shift_JIS で構築されている従来の Webサイトを扱う場合に場合に覚えておいて損はない方法です。仮に HTMLファイルの文字コードが Shift_JIS だったとしても、&#xNNNN; という文字参照形式で記載すれば Unicode だけにある新しい文字を文字化け無く表示することが可能です。 (ただし、閲覧側のブラウザやOSがある程度新しいものであることが条件です。)
文字参照は以下のように HTML::Entities モジュールを使って出力します。これは漢字だけでなく、Shift_JIS の日本語の中にフランス語の「ç」や、ドイツ語の「ß」、スペイン語の「ñ」を混ぜて表示したいというような場合にも使えます。 (ただし、日本語フォントのままだと文字化けします。CSSでのフォント指定もお忘れなく!)
use strict;
use warnings;
use utf8;
use HTML::Entities;
my $template = '...<p>__PLACE__</p>...<p>__PLACE2__</p>'; #Shift_JIS のHTMLテンプレート
$template =~ s/__PLACE__/encode_entities('〠123-456')/ge;
$template =~ s/__PLACE2__/encode_entities('フランス語の「ç」や、ドイツ語の「ß」、スペイン語の「ñ」')/ge;
binmode STDOUT, ':encoding(cp932)';
print $template; さて、今回はまとまったプログラムではなく、色々な場合に変えていかなければならないコードサンプルの紹介になりました。文字化けは、これ一本でOK、といったすっきりした解決のない、なかなか奥深い問題なのです。プログラマー的には頭が痛いわけですが、日本語が多くの文字と、それにこだわる豊かな文化を持っていることの証でもあるのです。大切にしたいですね。







