boost::filesystemと日本語

boost::filesystemはワイド文字が扱えないと書いたのと連動して、今回は日本語に限ったオハナシ。

文字コード

C++でプログラミングする際の話しなので必然的に文字コードについての知識が必要、ということになるんだが、とりあえず、

とかで勉強できるので目を通しておくと幸せになれるかも("文字コード==文字集合+符号化方法"とかはじめて知ったよ…。こういうレイヤー分けして区別しないと規格が多すぎて困るもんなー。)。現在日本語文字コードっつーとISO-2022-JPShift_JISEUC-JP・Unicode:UTF-16あたりを考慮すればいいと思うんだが、Unicode意識して使った事ないので今回は議論しない。

boost::fielsystemのname_check function

boost::filesystemは内部でstd::stringを使っているので、ワイド文字非対応と言えども日本語の値の代入はできる。まぁ「代入をするコードを書ける」と言った方がより的確なんだが。で、実際に代入したときに問題となるのがname_check functionによる自動チェック機能で、指定した処理系でファイル名に使ってはいけない文字が使われている場合、やさしく例外を投げてくれる

ここで問題になるのがどの文字がvalidでどの文字がinvalidなのかという基準だが、POSIXで許可されている文字を正規表現で表すと[0-9a-zA-Z\._-]、逆にWindowsでは許可されていない文字は同様に正規表現で[<>:\"/\\|]プラス0x0-0x1Fの範囲の値となる。POSIXの条件がかなりキツイが、portable_nameやposix_nameといったname_check functionを使わない限り、実はノーチェックなので問題ない*1。のでWindowsで使えない文字にしぼって議論する。

Shift_JISの場合

第2バイトに指定できる値が、文字"\"と"|"にかぶってしまうので一部使えない文字が出てくる。"\" : 0x5cはいわゆるダメ文字の[―ソЫⅨ噂浬欺圭構蚕十申曾箪貼能表暴予禄兔喀媾彌拿杤歃濬畚秉綵臀藹觸軆鐔饅鷭祥薌]、"|" : 0x7cは[−ポл榎掛弓芸鋼旨楯酢掃竹倒培怖翻慾處嘶斈忿掟桍毫烟痞窩縹艚蛞諫轎閖驂黥筇螬]が相当する。それぞれ一般的に使う文字がそれなりに含まれているので、もし使うなら注意しないといけない*2

で、name_check関数にnativeを指定すると第2バイトに0x5cの文字が入った文字列を代入することもできるんだが、boost::filesystemの各関数でパスの区切れ目として処理してしまう*3のでやっぱりうまくない。

ISO-2022-JPEUC-JPの場合

ISO-2022-JPでは参照する文字集合の切り替えに使うエスケープシーケンスの最初の文字[ESC] : 0x1bの時点でアウト。逆にEUC-JPは第1・第2バイトともinvalidな文字を使ってないので問題ない。これにより現在boost::filesystemで日本語パス/ファイル名を扱う場合EUC-JPで入出力するという選択肢しかない

*1:name_check fucntion補足を参照

*2:というか使わないほうが無難だね(笑。

*3:ディレクトリ/ファイル名の途中で区切られて変なパス名が出来上がる