Perl の Unicode 対応

UTF-8 フラグ?

自分がわかりにくかったところとか、重要そうな点をまとめておきます。

まず UTF-8 フラグについて。UTF-8 フラグという名前だからややこしいんだけれども、結局のところ、Perl の内部でマルチバイト文字を 1 文字として扱える状態というのが UTF-8 フラグがついた状態です。そしてそれはあくまで Perl の内部で使うためのもので、そのままの状態で外部へ出力できるわけではありません。

UTF-8 フラグがついた文字列というのは、UTF-8 だとかそういうのとは全く別の文字コード体系、だと考えればいいと思います。(それはそれで正確ではないかも知れませんが。。ASCII は UTF-8 と同じようですし。)

さて、ここまできて、取るべき選択肢は 2 つあります。まず、1 つめ。マルチバイト文字はこれまでどおりバイトコードとして扱う。2 つめは、Unicode に対応してマルチバイト文字も 1 文字として扱えるようにする。

もちろんこれまでどおりでも今のところ問題はなさそうですが、時代の流れとしては Unicode に対応すべきでしょう。簡単にその方法を書いておきます。

Unicode に対応した Perl プログラミング

まず、自分が書いたプログラムが UTF-8 で書いてあるかそうでないかによって変わってきます。

UTF-8 で書いてある場合、use utf8 プラグマを使って、UTF-8 で書かれてあることを Perl に知らせるとともに、標準入出力・及びエラー出力の文字コードを binmode で指定する必要があります。
例えば、Windows 環境で使用する場合、Shift-JIS での入出力が扱いやすいと思われるので、以下のようになります。

use utf8;
binmode STDOUT, ":encoding(shift_jis)";
binmode STDERR, ":encoding(shift_jis)";
binmode STDIN,  ":encoding(shift_jis)";

Shift_jis 以外の文字コードを使う場合は shift_jis の部分を対応する文字コードに変更する必要があります。 ただし、UTF-8 の場合は :encoding(文字コード) ではなく :utf8 を使います。 つまり、以下のようになります。

use utf8;
binmode STDOUT, ":utf8";
binmode STDERR, ":utf8";
binmode STDIN,  ":utf8";

まず、use utf8; で、ソースコードの文字列に UTF-8 フラグが付きます。 binmode STDIN, ":utf8"; で、標準入力から取得した文字列にも UTF-8 フラグが付きます。 ただし、標準入力の文字列が UTF-8 でない場合エラーになります。
内部的に Unicode で文字を扱うことが出来るようになりましたが、先に述べたようにそのまま出力することはできません。 よって、binmode STDOUT, ":utf8"; で、出力時に内部的なコードを UTF-8 に変換するように指定しています。

また、ソースコードが UTF-8 以外の場合は、下のように use encoding "文字コード" を使います。

use encoding "shift_jis";
# binmode STDOUT, ":shift_jis";
binmode STDERR, ":shift_jis";
# binmode STDIN, ":shift_jis"; use encoding すると自動的にそれと同じ文字コードが STDOUT と STDIN に適用される。

が、どうせ入出力の文字コードを指定できるのだから、UTF-8 でソースコードを記述し、use utf8; するのが一番いいような気がします。 encoding は使いにくいし。

ちなみにファイルの入出力では以下のように入出力の文字コードを指定することで内部的には UTF-8 フラグが付いた状態で扱えます。

サンプルコード

以下が、これまでのようにバイトコードをバイトコードのまま扱うプログラム。

;
#chomp $test;
print "入力されたのは \"" . $test . "\" です。\n";
print "入力された文字列の長さは " . length($test) . " です\n";
print "unpack すると " . unpack("H*", $test) . " となります。\n";

exit(0);]]>

「あいうえお」と入力すると、入力した文字数は 11 と出力されます。(改行コードも含めて)

F:\My Documents\Programming\Perl>perl charSet_all_s-jis.pl
Shift-JIS で書いたプログラムをバイトコードで処理する場合
文字列を入力してください: あいうえお
入力されたのは "あいうえお
" です。
入力された文字列の長さは 11 です
unpack すると 82a082a282a482a682a80a となります。

実際の文字数とプログラムがカウントした文字数が異なっています。(1 byte を 1 文字としてカウントしているため)

次に、ソースコードを UTF-8 で書いた場合です。

;
#chomp $test;
print "入力されたのは \"" . $test . "\" です。\n";
print "入力された文字列の長さは " . length($test) . " です。\n";
utf8::encode($test);
print "utf8::encode して unpack すると " . unpack("H*", $test) . " となります。\n";

exit(0);]]>

実行結果は以下の通り。

F:\My Documents\Programming\Perl>perl charSet_utf8.pl
  UTF-8 で書いたプログラムを内部的には Unicode で処理する場合
  文字列を入力してください: あいうえお
  入力されたのは "あいうえお
  " です。
  入力された文字列の長さは 6 です。
  utf8::encode して unpack すると e38182e38184e38186e38188e3818a0a となります。

ちゃんと文字列の長さが 6 と、(改行を含めた) 文字数と一致しています。

公開日: 2009.05.06, 更新日: 2009.05.06