Mac OS X の NFD 問題での対策諸々

おさらい。 ∥ Unicode正規化 - Wikipedia

  • 正規化形式
    • NFC: Normalization Form Canonical Compression | 文字に何がくっついていようと、組み合わせて作られた文字であろうと、「一文字」は「一文字」じゃ。圧縮形式。Linux のファイルシステムや Windows の NTFS などが普通に使っている。
    • NFD: Normalization Form Canonical Decompression | 濁点・半濁点を、あるいはウムラウト等のダイアクリティカルマークを、本体の文字とは分離してエンコードした形式。OS X の HFS+ が、これを採用してくれちゃっている。

基本としては、OS X 上に置かれるファイルは NFD であってくれて、Linux や Windows 上にあるファイルは NFC であってくれると平和で助かる。

追記(2016/09/29): コメントで指摘を頂いたんですが、確かに実際のところは HFS+ においては NFD 正規化する機能を有しているだけであって、Linux や Windows の方は慣習的に NFC 正規化されたファイル名を使っていてそれに対してファイルシステムは何の正規化もしていないだけなんですよね。私の Linux のファイルシステム中にも、うっかり NFC 正規化されたまま入れてしまってそのままになっているファイルがあります。

ファイルシステムの問題なのである

Mac OS X の HFS+ における NFD の濁点・半濁点の問題。

結局 HFS+ を通すと、何をどうしようと NFD に正規化されてしまうんだな。NFC で格納する手だては無いと。

$ basename /Users/knaka/Desktop/パピプペポ.pdf | iconv -f utf-8-mac -t utf-8 | dm
00000000 | E3 83 91 E3 83 94 E3 83 97 E3 83 9A E3 83 9D 2E | ................
00000010 | 70 64 66 0A                                     | pdf.
$ touch $(basename /Users/knaka/Desktop/パピプペポ.pdf | iconv -f utf-8-mac -t utf-8)
$ ll パピプペポ.pdf

表示手段

Mac ローカルでの表示に関する問題解決。基本的には、OS X 標準のツール群は、だいたい NFD について考慮してくれているようだ(あたりまえか)。なので、問題があるとしたら Homebrew などで入れたツールである。

GNU Screen

Homebrew の screen(1) も、NFD を手当てしていない。 ∥ GNU screen 最新版について - rcmdnk’s blog

なんと、OS X 標準のは、ちゃんと表示する。ただ、標準のは 256 色表示ができないのですよね。なので、手で入れます。 ∥ GNU screen 最新版について - rcmdnk’s blog

$ curl http://ftpmirror.gnu.org/screen/screen-4.2.1.tar.gz | tar zxvf -
$ cd screen-*/
$ curl https://gist.githubusercontent.com/mrkn/626040/raw/be6a04f0e64c56185ba5850415ac59dad4cd62a0/screen-utf8-nfd.patch | patch -p2
$ curl http://zuse.jp/misc/screen-utf8-osc.diff | patch -p2
$ ./configure --prefix=/usr/local --enable-colors256 && make
$ make install

転送手段

ネットワーク転送においての NFD 変換。Windows や Linux に送る際には、NFC に変換して欲しい。

Dropbox

◯: どうやら、NFC, NFD の手当てをしているみたいだ。クライアントの OS 種別は分かってますからね。さすが。

scp

✕: 何もしてくれない。

rsync

Homebrew で最新を入れれば ◯。--iconv オプションが使えるようになる。標準(Yosemite 同梱)の方は、バージョンが上がる気配はありませんね。

$ /usr/bin/rsync --version
rsync  version 2.6.9  protocol version 29
...
$ /usr/local/bin/rsync --version
rsync  version 3.1.1  protocol version 31
...
$ rsync --iconv=UTF8-MAC,UTF-8 rsc-ほげ.txt svr.example.com:/tmp/

とはいえこのオプションが効くのは rsync サーバのインターフェイスを通じてのやりとりの中でのパス名についてだけですので、よく考えると当たり前なのですが、たとえば「Mac のローカルにあるディレクトリと同名のディレクトリがリモートの Linux にも有ったらフェッチする」などの場合には、「ローカルにあるディレクトリ(NFD)と同名のディレクトリがリモートにも(NFC で)有ったらフェッチする」となるので、さらに一手間が必要です。

これは Mac 上の処理:

for dirabs in /hoge/fuga/*
do
  dirbase=$(basename "$dirabs")
  dirbase_nfc=$(echo "$dirbase" | iconv -f UTF8-MAC -t UTF-8)
  rsync "svc.example.com:/foo/bar/$dirbase_nfc/" "$dirabs/"
done

コピペで ls すると有るのに、rsync は「無いぞ無いぞ」とエラーを吐くので、しばらくハマりましたよ。面倒ね。

NFS

クライアントの Mac 側で、サーバが NFC であることを nfc オプションで指定すれば、正しく扱える(「/etc/auto_*」については右記なども。 ∥ Using the Mac OS X Automounter - Use Your Loaf)。

$ cat /etc/auto_knaka
arc -ro,nfc nfs://luminous/mrd/arc

sftp (sshfs via FUSE)

相手の SSH サーバが NFC だとハマるかと思ったのですが、変換する仕組みがありました。助かります。

$ sshfs -o modules=iconv,from_code=UTF-8,to_code=UTF-8-MAC svc.example.com:/arc /arc

当然経路も暗号化されるし(素の NFS や CIFS だと平文を飛ばす)、個人アカウントでアクセスするから ID マップの問題も生じないし(NFS や WebDAV でハマる)で、これは良いな…。

FAT な USB メモリで手渡し

「文字コードには、ローカルなコードセット(日本語の場合はCP932 Shift_JIS)が使われます」 ∥ FATファイルシステムのしくみと操作法

USB メモリ等で、なおも根強く使われ続ける FAT では、基本的に環境依存の L10N なので、ファイル名の文字コードに ASCII 以外を使えば問題が出る。今だと、NFC に揃えて zip アーカイブにでもして渡すのが正しいのだろうか。