Perl5.8 での Unicode 文字列の注意点
Amazon Search とかを EUC ベースから UTF8 ベースで実装し直したのですが、場合によって length や substr 等の文字列関数で処理が違うことが判明。備忘録として記事にしました。
Perl5.8 では Unicode 文字列に対して UTF8 フラグという内部データを設けて、その有無によって文字単位で扱うかバイト単位で扱うかを決定しています。また UTF8 フラグの ON/OFF は utf8 モジュールのutf8::encode() と utf8::decode() によって操作できるようになっています。
バイト単位でUnicode文字列を扱いたいときは、utf8::encode() によって、UTF8 フラグを OFF に、文字単位でUnicode文字列を扱いたいときは、utf8::decode() によって、UTF8 フラグを ON にする必要があります。
また、UTF8 フラグが OFF になっている場合にutf8::encode() を何度も実行すると、おかしな事になるので、UTF8 フラグの有無を調べる utf8::is_utf8() メソッドで適宜調べる必要があります。
これらの utf8 モジュールのメソッドを適宜使い分けて文字列操作をしないと、Unicode文字列操作は予期しない結果(文字化け等)になってしまいます。
具体例をあげると、UTF8 で記述された次のプログラムを記述します(Perl5.8.1以降)、
これを実行すると、
となります。はじめの例は、全角文字列がそれぞれ3バイト、半角文字列がそれぞれ1バイトで計算され、はじめの10バイトを取得すると、「あいう」+フラグデータを取得しています。おそらく文字列は文字数で計算する場合が多いと思います。その場合は、utf8::decode() を事前に実行しておけば、後者の結果が得られるということです。もちろん場合によっては、文字列操作後、utf8::encode() で元に戻しておく必要もあるので注意が必要です。
Perl5.8 では Unicode 文字列に対して UTF8 フラグという内部データを設けて、その有無によって文字単位で扱うかバイト単位で扱うかを決定しています。また UTF8 フラグの ON/OFF は utf8 モジュールのutf8::encode() と utf8::decode() によって操作できるようになっています。
バイト単位でUnicode文字列を扱いたいときは、utf8::encode() によって、UTF8 フラグを OFF に、文字単位でUnicode文字列を扱いたいときは、utf8::decode() によって、UTF8 フラグを ON にする必要があります。
また、UTF8 フラグが OFF になっている場合にutf8::encode() を何度も実行すると、おかしな事になるので、UTF8 フラグの有無を調べる utf8::is_utf8() メソッドで適宜調べる必要があります。
これらの utf8 モジュールのメソッドを適宜使い分けて文字列操作をしないと、Unicode文字列操作は予期しない結果(文字化け等)になってしまいます。
- スポンサーリンク -
具体例をあげると、UTF8 で記述された次のプログラムを記述します(Perl5.8.1以降)、
use utf8; use XML::Parser; my $str = "あいうえおアイウエオ123"; utf8::encode($str); print "UTF8 flg:", utf8::is_utf8($str), "\n" ; print "Length:", length($str), "\n"; print "Substr:", substr($str,0,10), "\n\n"; utf8::decode($str); print "UTF8 flg:", utf8::is_utf8($str), "\n" ; print "Length:", length($str), "\n"; print "Substr:", substr($str,0,10), "\n\n";
これを実行すると、
UTF8 flg:
Length:33
Substr:あいう
UTF8 flg:1
Length:13
Substr:あいうえおアイウエオ
Length:33
Substr:あいう
UTF8 flg:1
Length:13
Substr:あいうえおアイウエオ
となります。はじめの例は、全角文字列がそれぞれ3バイト、半角文字列がそれぞれ1バイトで計算され、はじめの10バイトを取得すると、「あいう」+フラグデータを取得しています。おそらく文字列は文字数で計算する場合が多いと思います。その場合は、utf8::decode() を事前に実行しておけば、後者の結果が得られるということです。もちろん場合によっては、文字列操作後、utf8::encode() で元に戻しておく必要もあるので注意が必要です。
- スポンサーリンク -
コメントやシェアをお願いします!
drk
after さん>ちょっとバグってました。すいません。現在は修正されていると思うのですが、いかがでしょうか?
※中継君とうのキャッシュをクリアして頂いて再度ご確認ください。
after
お世話になってます
で、文字化けするようになってしまったんですが、こちらで何かすることはありますか?