Humanity

Edit the world by your favorite way

Perlのutf8についてとか

さっきのエントリでバイト列がUTF8な文字列として認識されないとか言ってたんだけど無事できたー。
まぁさっきのエントリに追記してもいいんだけどPerlエンコードがらみのことはよく分かってないので別エントリとしてメモ。


まず、さっきのエントリの解答。

#!/usr/bin/env perl
use strict;
use warnings;
use Carp;

sub assert {
    croak unless $_[0];
}


# なくても結果は同じ。
# utf8::decode()使うのに必要かと思ったけど
# シンボルパッケージテーブル見たら
# デフォルトでuseされてるみたい?
use utf8;

sub bytes_str_to_utf8 {
    my $bytes = shift;

    # http://d.hatena.ne.jp/Gemma/20090617/1245266779より。
    # どっちでも同じだけど後者の方が断然スマート。。。
    # $bytes =~ s{(..)}{
    #     pack 'C', hex($1) & 0xff
    # }exg;
    $bytes = pack 'H*', $bytes;

    # バイト列をutf8な文字列として認識する。
    utf8::decode($bytes);
    return $bytes;
}

my $bytes_str = 
          "e4bba5e4b88be381aee69687e5ad97e58897e381af5554462d38e38292e69687e5ad97"
        . "e382a8e383b3e382b3e383bce38387e382a3e383b3e382b0e5bda2e5bc8fe381a8e381"
        . "99e3828b3136e980b2e695b0e381aee38390e382a4e38388e58897e381a7e38182e3828be38082";
assert(length($bytes_str) % 2 == 0);

{
    local $\ = "\n";

    # これをしてないと
    # 255より文字コードがでかいと
    # Wide character in 'print'と言われる。
    # この適用範囲はこのブロックを外れてからも続く。
    binmode STDOUT, ":utf8";

    my $utf8_str = bytes_str_to_utf8($bytes_str);

    print $utf8_str;
    print length $utf8_str;    # 文字数
    print do { use bytes; length $utf8_str };    # バイト数

    print "is utf8?:" . utf8::is_utf8($utf8_str);
}

出力結果

以下の文字列はUTF-8を文字エンコーディング形式とする16進数のバイト列である。
41
109
is utf8?:1


バイト列をUTF8の文字列として認識するにはutf8::decode($bytes)をする必要があるらしい。
あとちょっとしたことだけどutf8::decode($bytes)は何故か1を返す。

(decode、encodeがちょっとごっちゃになってたんだけども、弾さんが
「入力した文字列はEncode::decode(入ってきた文字列のエンコード, 文字列)、
出力するときはEncode::encode(出力するエンコード, 文字列)」
と言ってたのをかろうじて思い出した)


binmodeについてはまた別エントリで書くとして、
とりあえずutf8.pmとbytes.pmの違いみたいなサンプルコードを勉強のために書いてみたので貼っておく。