Encode::UTF8Mac

探したのだけど作っている人がいなかったので、いわゆるutf-8-macと呼ばれるエンコーディングを追加するEncode::Encodingをつくりました。

https://github.com/tomill/Encode-UTF8Mac

use Encode;
use Encode::UTF8Mac;

print Encode::encode('utf-8-mac', '蘄藭づけ');

use Path::Class;
for my $entry (dir(".")->children) {
    my $filename = Encode::decode('utf-8-mac', $entry);

}

反応みてPODちゃんと書いたらUPしようと思っている

Macのファイル名はNFDされている

MacOSXでは文字コードはutf-8エンコーディングが使われているのだけど、UnicodeのNFDという正規化がされている。

具体的には、「だ」みたいな濁点つきカナが、「た」+「゛」の二つのUnicodeで表現されたりしてる。゛は「てん」で変換してでる濁点マーク U+309B ではなく、Unicodeで組み合わせる用として用意されている点 U+3099

ふつうにdecode('utf-8')すると「だ」が一文字じゃなく2つのUnicodeになるわけです。

なので、perlではファイル名はをdecodeしたあとUnicode::NormalizeのNFC関数(NFCは「た」+「゛」的なものを「だ」と扱う正規化名)を使ってくっつけるという方法が使えます。

use Encode;
use Unicode::Normalize;

my $filename = Encode::decode('utf-8', $filename);
$filename = Unicode::Normalize::NFC($filename);

ちなみにファイルやディレクトリを作成する時は、NFDな(「だ」のようにくっついた)ものをわたしても、Mac側で勝手にNFCします。逆に言うと、ファイルシステムに出す時はNFD化して出す、ということはしなくてもいい。

utf-8-macとは

ところが、UnicodeのNFCは「た」+「゛」→「だ」のようなそのままのものだけではなく、「蘄」を「福」とする、などの正規化も行なってしまいます。

Macでは「蘄」は使えないのか?というとそんなことはない。じゃあMacはどうしてるのかというと、特定の範囲はNFDしない、という特例付きでNFDしています。

http://developer.apple.com/library/mac/#qa/qa2001/qa1173.html

HFS Plus は、Normal Form D の変形を使用しており、U+2000 から U+2FFF、U+F900 から U+FAFF、および U+2F800 から U+2FAFF は分解されません

perlでutf-8-macなdecodeをしたい

じゃこれを判断して 蘄藭づけ.txt みたいなファイルを福神づけ.txt じゃなくちゃんと 蘄藭づけ.txt とdecodeするにはどうしたらよいかというと、osxに付属のiconvは独自のutf-8-macというエンコーディングを使えるようにしてるらしく、それで変換すればいいらしい。

ただこれだけのために使いたくないなあと。そこで、特例の範囲をのぞいてNFC/NFDするエンコーディングを作りました。

なんで誰もつくってないんだ??!とおもったのですが、実際は、これら特例の範囲はほぼ超難しい漢字とかだけなので、影響するのはアジア圏の一部、ということで上記の Unicode::Normalize::NFC() 作戦でほぼ問題はないということから作られてなかったのかもしれないですね。

これがあれば、ファイル名を出し入れする時にEncodeのみでいけるので、使うエンコーディングは、日本語の場合こんな感じにするだけでよくなるんじゃないかと思います。

$encoding = do {
    if ($^O eq 'MSWin32') {
        'cp932';
    } elsif ($^O eq 'darwin') {
        'utf-8-mac';
    } else {
        'utf-8';
    }
};