Kawa.netxp Shift_JIS に含まれない文字をエスケープ (Jcode.pm編)

下記の『﨑』『鄧』『髙』の3文字は 現在は Unicode を使って表現できますが、 Shift_JIS には含まれない文字のため、 クライアント環境によっては表示できない場合は依然多く、文字化けしやすいです。

漢字 CP932 EUC-JP UCS2 UTF8 補足
FAB1 - FA11 EFA891 山+立+可
FBB9 8FE2C7 9127 E984A7 とう小平
FBFC - 9AD9 E9AB99 ハシゴ高

しかし HTML での利用においては、 最近のブラウザは &#xHHHH; 形式で Unicode のコード(UCS2)を指定すると、 クライアント側に該当フォントがあれば、表示できるようになります。

本ページでは、Perl+Jcode.pm を使って その自動変換を行うパッチをご紹介します。

更新履歴

Perl 5.8.x+Encode.pm

Perl 5.8.x では、コード変換に標準モジュールの Encode.pm を利用できます。

Unicode (UTF-8) → Shift_JIS のコード変換を行う際に XMLCREF オプションを利用すると、 Unicode にあって Shift_JIS に含まれない文字が &#xHHHH; の形式に変換されます。

以下のサンプルでは、『﨑鄧髙』の3文字を UTF-8 から Shift_JIS に変換して表示しています。

#!/usr/bin/perl
use Encode;
my $text = "\xEF\xA8\x91\xE9\x84\xA7\xE9\xAB\x99";
Encode::from_to( $text, "UTF8", "Shift_JIS", Encode::XMLCREF );
print $text, "\n";

の実行結果は『﨑鄧髙』とエスケープされました。 この3文字は Shift_JIS には含まれないため、 Encode.pm によって Unicode 番号にエスケープされています。 もちろん、これ以外の通常の文字については、正しく Shift_JIS で出力されます。 また、

#!/usr/bin/perl
use Encode;
my $text = "\xEF\xA8\x91\xE9\x84\xA7\xE9\xAB\x99";
Encode::from_to( $text, "UTF8", "CP932", Encode::XMLCREF );
print $text, "\n";

のように、"Shift_JIS" でなく "CP932" を指定した場合は IBM 拡張文字のコードを利用できるため、 『﨑鄧髙』の文字をそのまま出力することもできます。

Perl 5.005/5.6.1+Jcode.pm

Perl 5.005 および Perl 5.6.1 では、Encode.pm モジュールが利用できないため、 コード変換は Jcode.pm を利用します。 Jcode.pm の内部コードは、JIS X 0212 に対応した EUC-JP になっています。 Unicode を Shift_JIS に変換する場合、 Unicode→EUC-JP→Shift_JIS と順に変換されます。

このとき、Unicode→EUC-JP の変換時には、 Unicode に表現できて EUC-JP で表現できない文字は『??』に変換されます。 また、EUC-JP→Shift_JIS 変換時には、 EUC-JP で表現できて Shift_JIS で表現できない文字は『〓』に変換されます。 (なぜ統一していないのかは分かりませんが、区別がつくのは便利ですね)

#!/usr/bin/perl
use Jcode;
my $text = "\xEF\xA8\x91\xE9\x84\xA7\xE9\xAB\x99";
Jcode::convert( \$text, "sjis", "utf8" );
print $text, "\n";

Encode::from_to と Jcode::convert では コードの指定順が逆なのに注意してください。

この結果は、『??〓??』となります。 まず『﨑』と『髙』は EUC-JP(JIS X 0212)で表現できないため、 『??』に変換されます。 対して『鄧』は EUC-JP では表現できますが、Shift_JIS(≠CP932)で表現できないため、 今度は『〓』に変換されます。

Perl 5.005/5.6.1+Jcode.pm+パッチ適用

上記のような Shift_JIS 環境での文字化けは避けたいところですが、 Jcode.pm には、Encode.pm の XMLCREF のような便利なオプションがありません。 そこで Jcode.pm でも XMLCREF のように &#xHHHH; の形式にエスケープする パッチプログラムを作成しました。

下記の手順でパッチを適用・インストールします。

$ wget http://openlab.jp/Jcode/Jcode-2.00.tar.gz
$ wget http://www.kawa.net/works/jcode/jcode-xmlcref-20050117.patch
$ tar zxf Jcode-2.00.tar.gz
$ cd Jcode-2.00
$ patch -p0 < ../jcode-xmlcref-20050117.patch
$ perl Makefile.PL && make
# make install

このパッチを適用した Jcode.pm では、

がそれぞれ &#xHHHH; 形式にエスケープされます。同じ

#!/usr/bin/perl
use Jcode;
my $text = "\xEF\xA8\x91\xE9\x84\xA7\xE9\xAB\x99";
Jcode::convert( \$text, "sjis", "utf8" );
print $text, "\n";

を実行した結果は、『&#xFA11;&#x9127;&#x9AD9;』となって エスケープされました。 もちろん、これ以外の通常の文字については、正しく Shift_JIS で出力されます。

Perl 5.8.1以降+Jcode.pm 1.99以降

Jcode.pm 1.99 以降のバージョンでは、 Jcode.pm の内部的に Encode.pm を利用するように変更されました。

PerlJcode.pm処理エンジン内部コード対応
5.005〜5.8.0-Jcode.pm独自 EUC-JP本パッチを適用してください
5.8.1〜〜0.88Jcode.pm独自 EUC-JP本パッチを適用してください
5.8.1〜1.99〜Encode.pm利用 UTF-8fallback メソッドを利用してください

Perl 5.8.1 以降と組み合わせた場合、fallback メソッドが利用できるため、 本パッチの利用は不要になります。(適用しても無視されます)

my $text = "\xEF\xA8\x91\xE9\x84\xA7\xE9\xAB\x99";
my $j = jcode($text);
$j->can("fallback") and $j->fallback(Jcode::FB_XMLCREF());
my $sjis = $j->sjis;

このように記述することで、 Perl 5.8.1 以降では Enccode.pmでXMLCREF を指定したのと同じ効果を得られます。
ただし、Perl 5.8.1 未満を利用した場合は、fallback メソッドは利用できないため、 効果はありません。(本パッチの適用が必要です)

補足

コメントはこちらへ by AjaxCom

その他のページへのリンク

このページへのトラックバック by AjaxTB

トラックバックURL:http://www.kawa.net/service/tb/ajaxtb.cgi/works/jcode/uni-escape.html

Kawa.netxp © Copyright 2004-2006 Yusuke Kawasaki