メメメモモ

プログラミング、筋トレ、ゲーム、etc

perlのデコードとエンコードについて(1)

デコードする

ある文字列が何文字あるのかを求めるプログラムを書くとします。
perlにはlengthという関数があるので、これを使って以下の様なプログラムを書きました。

# UTF-8で保存したファイル
use strict;
use warnings;

my $str = 'ハローワールド';
my $length = length $str;

print $length . "¥n"; # 21が出力される

「ハローワールド」は7文字なので、「7」という数字が出力されれば嬉しいですね。
でも実際には「21」と出力されてしまいます。
これは「21バイト」を意味します。
「ハローワールド」は、1文字3バイトで表せられるので、「3 x 7 = 21」です。


つまり、perlには、「ハローワールド」は文字列としてではなく、単なるバイト列として認識されてしまっているのです。
perlに「ハローワールド」を文字列として扱ってもらうためには「デコード」を行う必要があります。
「デコード」は、以下のようにEncodeモジュールを使って行います。

# UTF-8で保存したファイル
use strict;
use warnings;
use Encode;

my $str = 'ハローワールド';

# デコード
my $decoded_str = Encode::decode('utf-8', $str);

my $length = length $decoded_str;

print $length . "¥n"; # 7が出力される


デコードされた文字列は、perlに文字列としてちゃんと扱われるようになります。
デコードされた文字列をlength関数に渡すと、きちんと文字数が返ってくるようになります。


ここでデコードされた文字列を「内部文字列」と呼びます。
perlが処理するための独自の文字コードのようなものです。

上記の例では、「UTF-8の文字列をデコードして、内部文字列に変換した」と言えます。
例えば、「Shift_JISの文字列をデコードして、内部文字列に変換」するなら、
以下の様なプログラムを書きます。

my $decoded_str = Encode::decode('Shift_JIS', $str);


このように、まずは文字列をデコードして内部文字列に変換する必要があります。
そうでないと、length関数の例のように、期待した結果が出なくなってしまいます。

エンコードする

以下のようなプログラムを書くと警告が出ます。

use strict;
use warnings;
use Encode;

my $str = 'ハローワールド';

my $decoded_str = Encode::decode('utf-8', $str);

print $decoded_str . "¥n";

Wide character in print at test.pl line 9.

これは、内部文字列のまま標準出力をしてしまったからです。
内部文字列はperl独自のものなので、標準出力やファイル書き込みやDBに格納するなど、外に出すときには内部文字列を「エンコード」する必要があります。
エンコード」は、以下のようにEncodeモジュールを使って行います。

use strict;
use warnings;
use Encode;

my $str = 'ハローワールド';
my $decoded_str = Encode::decode('utf-8', $str);

# エンコード
my $encoded_str = Encode::encode('utf-8', $decoded_str);

print $encoded_str . "¥n";

これで通常にutf8の文字列が出力されるようになりました。


また、Shift_JISの文字列で出力したい場合は、以下のようにエンコードします。

my $encoded_str = Encode::encode('Shift_JIS', $str);


このように、外に出力する場合は、何かの文字コードエンコードするようにします。