Perl 5.6.1でのUTF-8の処理の方法

CGIテクニック集トップへ





概要

Perl 5.6.1でUTF-8で記述されたファイルの読み書きの方法です。Perl 5.8では、Encode.pmを使って簡単に処理できるのですが、Encode.pmは、5.7.3以降でしか使えないので、Perl 5.6.1でUTF-8を処理する場合は、特殊な処理をしないといけません。

Pelr 5.6.1では、「use Encode」「binmode STDOUT, ":encoding(utf8)"/binmode STDOUT, ":utf8"」「open FILE, "<:encoding(utf8)", file/open FILE, "<:utif8", file」「decode/encode」「use open ":encoding(utf8)"/use open ":utf8"」が使えません。 「use encoding "utf8"」は使えますが、buggyなので勧められないと言われています。 この方法は、ブログ風日記帳で使われています。

この例では、入力ファイルも出力ファイルもUTF-8で記述されています。

必用な処理

  1. スクリプト自体は、UTF-8で記述する。
  2. ファイルを読み込む。
  3. 入力した文字列をデコードする。
  4. 処理する。
  5. エンコードして表示する。

サンプルコード

 use utf8;
 
 open (IN, "< utf8in.txt");
 open (OUT, "> utf8out.txt");
 
 while (<IN>){
    my $text = mydecode("$_");
    print OUT myencode("$text");
    print myencode("$text");
 }
 
 close (IN);
 close (OUT);
 
 sub mydecode {
     my $str = shift;
     return pack "U0C*", unpack "C*", $str;
 }
 
 sub myencode {
     my $str = shift;
     return pack "C*", unpack "U0C*", $str;
 }

コードの解説

サンプルコードと同じことををPerl 5.8で実現するには以下の方法があります。他にも方法はたくさんあります。

 use utf8;
 use open IO, ":encoding(utf8)";
 
 binmode STDOUT, ":encoding(utf8)";
 
 open (IN, "< utf8in.txt");
 open (OUT, "> utf8out.txt");
 
 while (<IN>){
    print OUT;
    print;
 }
 
 close (IN);
 close (OUT);

上記と同等の事をPerl 5.6.1では、以下の作業が必要になります。

 use utf8;

utf8プラグマを使用する。これによってこのスクリプトで使われる文字列は、utf8であるとPerlが認識します。


 open (IN, "< utf8in.txt");
 open (OUT, "> utf8out.txt");

入力ファイルと出力ファイルは、普通にopenします。


 while (<IN>){
    my $text = mydecode("$_");

ファイルハンドルから読み込んだ文字列をデコードします。mydeocodeの関数は、以下です。

 sub mydecode {
     my $str = shift;
     return pack "U0C*", unpack "C*", $str;
 }

ここでは、文字列をキャラクターでunpackして、再度Unicodeでpackしています。 この部分で、文字列の情報を一切変えずにPerlにこの文字列がUTF-8だということを教えています。実際にはUTF-8フラグを文字列に付加しています。Encode.pmを使った時のdecode("utf8",$_)と同じような動作になります。上記の5.8の例では、「use open」でその機能を果たしています。

    print OUT myencode("$text");

ファイルに出力する際には、UTF-8フラグを落として出力するために、エンコードしなければいけません。エンコードしなくてもUTF-8の文字列としてファイルには出力されますが、UTF-8の文字列を出力しているということでPerlの実行時に「Wide Character in print」というエラーが出ます。 myencodeの関数は以下のようになります。

 sub myencode {
     my $str = shift;
     return pack "C*", unpack "U0C*", $str;
 }

mydecodeとは逆にUnicodeでunpackし、キャラクターでpackし直しています。

    print myencode("$text");

ファイルに出力する時と同じ理由で、標準出力にプリントする時にもエンコードする必要があります。

 }
 
 close (IN);
 close (OUT);

ファイルをクローズします

関連するCGIテクニック

文字コード変換の仕方
文字コードの取得
メールのタイトル用にエンコードする方法
Shift_JISでの文字列サーチする方法
英文スパムなどのアスキーコードのみの文字列を排除する方法