2011年3月6日日曜日

ja_JP.UTF-8 vs ja_JP.utf8

それは某IRCチャンネルの何気ない一言から始まった.
@xxxx | .UTF-8 or .utf8?

僕は何も疑問を持たずに,こう答えた.
@Kojima | ja_JP.UTF-8

そしたら彼は,
@xxxx | .utf8 on 'locale -a'
と返答してきた.

確かに,手元の環境で
locale -a
を実行してみると,utf8 になっている.
$ locale -a
C
POSIX
en_US
en_US.iso88591
en_US.utf8
ja_JP
ja_JP.eucjp
ja_JP.ujis
ja_JP.utf8
japanese
japanese.euc

@matsuu 先生が以前 eselect locale を入れたときにこうつぶやいていたのを思い出したので,「matsuu先生がこういってるんだから,.UTF-8なんだよ!」としておいた.

ja_JP.utf8ではなくja_JP.UTF-8で設定すべし RT @naota344: 気がつけば @matsuu せんせーの eselect locale が入っていた。 eselect locale ja_JP.utf8 しておけばいいんだろうか…。less than a minute ago via web



とはいえ,ちょっと気になったので調べてみた.


LFS のドキュメントにこんな記述がある.
キャラクターマップはたくさんの別名を持つことが出来ます。 例:“ISO-8859-1”は、“iso8859-1”と“iso88591”として参照されます。 いくつかのアプリケーションは、様々な別名を正しく取り扱えません(例:“UTF-8”は、“utf8”ではなく“UTF-8”と書く必要がある)。

いくつかのアプリケーションは "UTF-8" と書いておかないといけないらしい.

"UTF-8" と書く理由はわかったけど,"utf8" と "UTF-8" は同価なのだろうか.

"locale -a" の結果はどこから持ってきてるのか調べてみる

$ strace locale -a
(snip)
open("/usr/lib64/locale/locale-archive", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=3677376, ...}) = 0
(snip)
"/usr/lib64/locale/locale-archive" を参照しているようだ.
これはきっと localedef で作られるはずだ,ということで localedef のコードを追ってみた.

glibc-2.11.2 の intl/l10nflist.c:_nl_normalize_codeset で以下のような処理をしていた.

347   if (retval != NULL)
348     {
349       if (only_digit)
350         wp = stpcpy (retval, "iso");
351       else
352         wp = retval;
353 
354       for (cnt = 0; cnt < name_len; ++cnt)
355         if (isalpha ((unsigned char) codeset[cnt]))
356           *wp++ = tolower ((unsigned char) codeset[cnt]);
357         else if (isdigit ((unsigned char) codeset[cnt]))
358           *wp++ = codeset[cnt];
359 
360       *wp = '\0';
361     }

locale-archive に書き込む際に,アルファベットは小文字に,アルファベットと数字以外は無視するようにしているようだ.

ちなみに,LC_* とか LANG のシンタックスは次のような形式らしい.
[language[_territory][.codeset][@modifier]]


結論

"ja_JP.utf8" も "ja_JP.UTF-8" も同じ意味.しかし,一部のアプリケーションでは ".UTF-8" と書かなければ正常に動作しないことがあるので "ja_JP.UTF-8" が推奨される.


たぶん.