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以降)、
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:あいうえおアイウエオ

となります。はじめの例は、全角文字列がそれぞれ3バイト、半角文字列がそれぞれ1バイトで計算され、はじめの10バイトを取得すると、「あいう」+フラグデータを取得しています。おそらく文字列は文字数で計算する場合が多いと思います。その場合は、utf8::decode() を事前に実行しておけば、後者の結果が得られるということです。もちろん場合によっては、文字列操作後、utf8::encode() で元に戻しておく必要もあるので注意が必要です。
- スポンサーリンク -