Encodeを使っても文字化けするとき
Encodeは特定のエンコーディングにしたがって配列されたバイナリを
たとえば、
use strict;
use warnings;
use Encode;
my $binary = pack('C*', 0x87, 0x40); # ①;
my $string = decode(shiftjis => $binary);
print encode(shiftjis => $string);
この場合は、
use strict;
use warnings;
use Encode;
my $binary = pack('C*', 0x87, 0x40); # ①;
my $string = decode(cp932 => $binary);
print encode(cp932 => $string);
あるいはCPANからEnocde::JIS2Kというモジュールをインストールして、
use strict;
use warnings;
use Encode;
use Encode::JIS2K;
my $binary = pack('C*', 0x87, 0x40); # ①;
my $string = decode(shiftjis2k => $binary);
print encode(shiftjis2k => $string);
もっとも、
文字化けを許容したくない場合
まったく毛色の異なるエンコーディングであればencodeの結果を見れば一目瞭然とはいえ、
Encodeは、
処理の自動化よりもデータの整合性のほうが大事な場合は、
use strict;
use warnings;
use Encode;
my $binary = pack('C*', 0x87, 0x40); # ①;
my $string = decode(shiftjis => $binary, Encode::DIE_ON_ERR);
print encode(shiftjis => $string);
文字参照を利用する
大勢に影響を及ぼさなければ多少の文字化けは許容するけれど、
use strict;
use warnings;
use Encode;
my $binary = pack('C*', 0x87, 0x40); # ①;
my $string = decode(shiftjis => $binary, Encode::FB_PERLQQ); # \x87@
print encode(shiftjis => $string);
この例では、
このチェックフラグは、
use strict;
use warnings;
use Encode;
my $binary = pack('C*', 0x87, 0x40); # ①;
my $string = decode(cp932 => $binary); # ひとまず正しい内部表現に
print encode(shiftjis => $string, \&check); # \x{2460}
sub check {
my $binary = shift;
sprintf "\\x{%04x}", $binary;
}
自分でエンコーディングを用意する
チェックフラグ/
自分でエンコーディングを用意する、
新しいエンコーディングモジュールの作り方については、
enc2xsを使う場合は.ucmという拡張子を持つマッピングテーブルを先に用意しておく必要があります。このテーブルはEncode独自のものではなくICU (International Components for Unicode)プロジェクトでも使われている標準的なマッピングのサブセットにあたるもので、
適当なディレクトリを用意したら、
それが済んだら、
続いてこのようなコマンドを実行すると、
> enc2xs -M ShiftjisWithCircledNumbers shiftjis_with_circled_numbers.ucm
ここまでできたら、
ためしにこのようなテストスクリプトをtest.
use strict;
use warnings;
use Encode;
use Encode::ShiftjisWithCircledNumbers;
use Test::More;
{
my $binary = pack('C*', 0x82, 0xA0); # あ;
my $string = decode(shiftjis_with_circled_numbers => $binary);
is $binary => encode(shiftjis_with_circled_numbers => $string);
}
{
my $binary = pack('C*', 0x87, 0x40); # ①;
my $string = decode(shiftjis_with_circled_numbers => $binary);
is $binary => encode(shiftjis_with_circled_numbers => $string);
}
done_testing;
マッピングを追加する
では、
enc2xsのPODにも説明があるように、
Unicodeの文字IDはUnicodeサイトのチャートを調べればわかりますが、
> perl -MEncode -MTerm::Encoding -e "print encode(null => decode(Term::Encoding::get_encoding, q/①/), Encode::FB_PERLQQ)"
バイナリ表現は、
> perl -MEncode -e "print decode(null => q/①/, Encode::FB_PERLQQ)"
フォールバックフラグは、
同じようにほかの丸数字についてもIDとバイナリ表記を調べていくと、
<U2460> \x87\x40 |0 # CIRCLED DIGIT ONE
<U2461> \x87\x41 |0 # CIRCLED DIGIT TWO
<U2462> \x87\x42 |0 # CIRCLED DIGIT THREE
<U2463> \x87\x43 |0 # CIRCLED DIGIT FOUR
<U2464> \x87\x44 |0 # CIRCLED DIGIT FIVE
<U2465> \x87\x45 |0 # CIRCLED DIGIT SIX
<U2466> \x87\x46 |0 # CIRCLED DIGIT SEVEN
<U2467> \x87\x47 |0 # CIRCLED DIGIT EIGHT
<U2468> \x87\x48 |0 # CIRCLED DIGIT NINE
<U2469> \x87\x49 |0 # CIRCLED NUMBER TEN
<U246A> \x87\x4A |0 # CIRCLED NUMBER ELEVEN
<U246B> \x87\x4B |0 # CIRCLED NUMBER TWELVE
<U246C> \x87\x4C |0 # CIRCLED NUMBER THIRTEEN
<U246D> \x87\x4D |0 # CIRCLED NUMBER FOURTEEN
<U246E> \x87\x4E |0 # CIRCLED NUMBER FIFTEEN
<U246F> \x87\x4F |0 # CIRCLED NUMBER SIXTEEN
<U2470> \x87\x50 |0 # CIRCLED NUMBER SEVENTEEN
<U2471> \x87\x51 |0 # CIRCLED NUMBER EIGHTEEN
<U2472> \x87\x52 |0 # CIRCLED NUMBER NINETEEN
<U2473> \x87\x53 |0 # CIRCLED NUMBER TWENTY
encode専用のマッピングを追加する
Encodeはさまざまな環境で使われますから、
たとえば、
このように、
<U2460> \x28\x31\x29 |1 # CIRCLED DIGIT ONE
<U2461> \x28\x32\x29 |1 # CIRCLED DIGIT TWO
<U2462> \x28\x33\x29 |1 # CIRCLED DIGIT THREE
<U2463> \x28\x34\x29 |1 # CIRCLED DIGIT FOUR
<U2464> \x28\x35\x29 |1 # CIRCLED DIGIT FIVE
<U2465> \x28\x36\x29 |1 # CIRCLED DIGIT SIX
<U2466> \x28\x37\x29 |1 # CIRCLED DIGIT SEVEN
<U2467> \x28\x38\x29 |1 # CIRCLED DIGIT EIGHT
<U2468> \x28\x39\x29 |1 # CIRCLED DIGIT NINE
<U2469> \x28\x31\x30\x29 |1 # CIRCLED NUMBER TEN
<U246A> \x28\x31\x31\x29 |1 # CIRCLED NUMBER ELEVEN
<U246B> \x28\x31\x32\x29 |1 # CIRCLED NUMBER TWELVE
<U246C> \x28\x31\x33\x29 |1 # CIRCLED NUMBER THIRTEEN
<U246D> \x28\x31\x34\x29 |1 # CIRCLED NUMBER FOURTEEN
<U246E> \x28\x31\x35\x29 |1 # CIRCLED NUMBER FIFTEEN
<U246F> \x28\x31\x36\x29 |1 # CIRCLED NUMBER SIXTEEN
<U2470> \x28\x31\x37\x29 |1 # CIRCLED NUMBER SEVENTEEN
<U2471> \x28\x31\x38\x29 |1 # CIRCLED NUMBER EIGHTEEN
<U2472> \x28\x31\x39\x29 |1 # CIRCLED NUMBER NINETEEN
<U2473> \x28\x32\x30\x29 |1 # CIRCLED NUMBER TWENTY
decode専用のマッピングを追加する
逆に、
<U0031> \x82\x50 |3 # DIGIT ONE
同じ方法でほかの全角英数字を半角化したり、
さらに複雑なマッピングをしたい場合
マッピングテーブルを使ったエンコーディングは書くのも楽ですし、
たとえば、
このような場合は、
やり方はいろいろありますが、
続いて、
package #
Encode::ShiftjisWithCircledNumbers::Main;
use strict;
use warnings;
use Encode;
use base 'Encode::Encoding';
__PACKAGE__->Define('shiftjis_with_circled_numbers');
sub decode ($$;$) {
my ($self, $octets, $check) = @_;
my $string = Encode::decode(_shiftjis_with_circled_numbers => $octets);
$string =~ s/\(([1-9]|1[0-9]|20)\)/chr(ord("\x{2460}") + $1 - 1)/ge;
$_[1] = $string if $check;
$string;
}
sub encode ($$;$) {
my ($self, $string, $check) = @_;
my $octets = Encode::encode(_shiftjis_with_circled_numbers => $string);
$_[1] = $octets if $check;
$octets;
}
実装としては内部表現にdecodeしたあと追加で置換しているだけですが、
みんなの利益になるものはCPANに
ここまでの内容が理解できれば、
ただし、
また、