やるきなし

2019/07/19 16:32 / Mac の NFD: Normalization Form Canonical Decompression 問題

MacではUnicode正規化形式としてNFD (Normalization Form Canonical Decompression; 正規化形式D)が利用されていて,Macユーザから日本語ファイル名のファイルを含むzipファイルが送られてくる際,そのファイル名がNFDになっていて Windows/Linux ユーザからすると感じが悪い.具体的には濁点(U+3099)・半濁点(U+309A)が文字として分離されている状態.

Windows ではエクスプローラーでひとまず表示はされる.手元の Linux の場合もそれっぽくは表示されるが ÿ という謎の文字が後に付加される...

そもそもファイル名がUTF-8でzipに含まれるので,Windows (Shift_JISを想定)では激しくファイル名が文字化けする.一方 Linux の unzip は UTF-8 を想定するので正しいファイル名で復号される(Windows 由来の Shift_JIS ファイル名が含まれるzipをLinuxで解凍する際は自動文字コード変換をする unar 等を使う).

いろいろやり方はあるが以下の Ruby script で濁点と半濁点だけなんとかする(あ゛などは想定外).

print STDIN.read.split("").inject([]){|r,i|
    if [0x3099,0x309a].include?(j=i.ord)
        i=(r.pop.ord + j - 0x3098).chr('UTF-8')
    end
    r<< i
}*""

convmv (Perl script)というコマンドが利用可能な場合は以下でまるごと置換可能.

% convmv * -f UTF-8 -t UTF-8 --nfc --notest

なお,Mac 環境から rsync する際は --iconv=UTF8-MAC,UTF-8 optionを付けると良いらしい.NFD/NFC変換がiconvでできないか手元(Linux)で試してみたが,以下のとおりサポートされていなかった.

iconv: conversion to `UTF-8-MAC' is not supported

参考:

追記 (2019/9/10)

Ruby で外部ライブラリを利用するならruby-unfを利用する.以下にパイプで送るとか.require "unf"String class に to_nfcto_nfd といった instance method が追加される.

ruby -e 'require "unf"; print STDIN.read.to_nfc'

なお ÿ が表示されてしまうのは screen のバグならしい.ただ,NFCと同様に表示されると,それはそれでNFDが見つけられなくてちょっと困るが...そもそも Mac の screen ユーザにとってはこれ死活問題かもしれない.screen に対するパッチ等,以下参照.