Perl 5.8以降でUnicodeを使う

Perlの5.8以降では、割と簡単にUnicodeが使えるようになっています。 自分の備忘録も兼ねて、簡単に使い方をまとめておきます。

Perlのsource codeをUnicodeで書く

Source codeをBOM(byte order mask)なしのutf8で書きます。 そして、次のように"use utf8;"と書いておけば、とりあえず source code内でUnicode文字列を扱うことができます。

#!/usr/bin/perl

use utf8;
#use strict;

$somevar = "漢字の文字列";
$somevar = "\x{3042}\x{3044}\x{3046}";   ## "あいう"

標準入出力の文字code

上記のようにすれば、source codeをUnicodeで書くことはできます。 しかし、このままでは文字列をprintするとutf8のまま出力されてしまいます。

普通は、実行環境に合った文字codeで出力したいと思いますので、次のように "use open"を使います。 このように書くと、STDIN, STDOUT, STDERRの3つの入出力はその環境に合った 文字codeで入出力されます。 例えばLANG=ja_JP.eucJPされているUn*xであれば、文字列はeuc-jpに自動変換 されて入出力されますし、日本語版Windowsであればshift-jisに自動変換され ます。

#!/usr/bin/perl

use utf8;
use open ":locale";
use open ":std";
#use strict;

print "漢字をstdoutに出力してみる\n";

exit 0;

Fileの入出力

続いて、fileの入出力です。 特定の文字codeを指定して読み書きする場合は、引数3つのopenを使って、第2 引数で文字codeを指定することができます。

#!/usr/bin/perl

use utf8;
use open ":locale";
use open ":std";
#use strict;

open(HANDLE, '>:encoding(euc-jp)', 'test.txt');
print HANDLE "この文字列はeuc-jpでtest.txtに書かれます\n";
close(HANDLE);

open(HANDLE, '<:encoding(euc-jp)', 'test.txt');
$str = <HANDLE>; # euc-jpの文字列を読んで、utf8に自動変換される
close(HANDLE);

exit 0;

utf16の出力

utf16の出力を行う場合はちょっとだけ注意が必要です。 Windows環境では、"\n"を"\r\n"に自動変換して出力しよ うとします。 この時、"\r"を2byteのutf16で追加してくれれば良いのですが、 1byteのまま追加されてしまうようです。
(なお、"\n"を"\n"のまま出力するUn*x環境では以下の問 題は発生しません)

例えば、次のように書いたとします。

#!/usr/bin/perl

use utf8;
use open ":locale";
use open ":std";
#use strict;

open(HANDLE, '>:encoding(utf16le)', 'test.txt');
print HANDLE "\x{feff}";                 # write BOM
print HANDLE "あいうえお\nかきくけこ";
close(HANDLE);

test.txtは16進表現で以下のような内容になります。"\r" (0x0d)が 1byteだけおかしな位置に入ってしまうため、1行目は読めますが2行目以降が utf16として壊れた文字列になってしまいます。

ff fe  42 30  44 30  46 30  48 30  4a 30  0d  0a 00  4b 30  4d 30  4f 30  51 30  53 30

これを回避するためには、以下のようにします。

#!/usr/bin/perl

use utf8;
use open ":locale";
use open ":std";
#use strict;

open(HANDLE, '>:raw:encoding(utf16le):crlf', 'test.txt');
print HANDLE "\x{feff}";                 ## write BOM
print HANDLE "あいうえお\nかきくけこ";
close(HANDLE);

">:raw:encoding(utf16le):crlf"という指定は、文字code変換す る前に"\r"を付け加え、utf16leに変換を行い、その後は "\r"などを付け加えることなくそのまま出力する、という意味です。 この結果、めでたく"\r"もutf16leに変換されて、次のように正しく 出力されます。

ff fe  42 30  44 30  46 30  48 30  4a 30  0d 00  0a 00  4b 30  4d 30  4f 30  51 30  53 30

ご意見、ご感想は、花房 真広 <webmaster@hanabusa.net>まで。メールする前にtop pageの注意書を読んでください。