2007-05-11

PerlではUTF8文字列でマルチバイトなファイル名をちゃんと扱えないという話も書いておいてくださいな

 PerlでのUTF8の扱いについて宣伝するのなら、それでファイル名を扱えないことについてちゃんとフォローしておいてくださいね。

(→追記があります。)

フォロー=「使えない可能性がありますよ」と補足すべきでは、という事です

 弾さんに言われなくてもPerlでマルチバイトなファイル名を扱うための提案はちゃんとしてるつもりです*1。だからこそ気になったわけで。

 UTF8文字列をファイル名として扱った場合にprint等と違ってwarningが出ないのは仕様としては不思議だな、と思いますけれど。

FUDというほどの内容ではないでしょう

 UTF8文字列をファイル名として指定したときにwarningを出さないのは不思議でもなんでもないそうですが、それではprintしたときにwarningを出すのは何故なんでしょうか。

 僕は同じ理由でwarningを出すべきなんじゃないかな、と思っただけです*2

ついでに言うと、本当に朝倉さんの要求を額面通りに受け取るなら、filenameプラグマは的はずれだろう(そんなことをするくらいならIO::Allにファイル名をいじくるオプションでもつけてもらった方がいい)。

 なるほど*3。すべてをPerlIOに任せるべき、というのはその通りかもしれません。

 ちなみに、filenameプラグマはencodingプラグマと整合的に使えるとうれしいな、というのが先にあったので、それが唯一の解だと思っているわけではないです。したがって、IO::Allにファイル名をいじくるオプションが付いたさいには、それを利用して既存の関数などをラッピングするプラグマを書くような気はします。

 あと、別に弾さんにつっかかってるつもりはないです。

 たまたまあの記事を読んで「日本語のファイルを開こうとしたらできないじゃん!」って人がいるかもなぁ、フォローといたほうがいいよなぁ、と思っただけです*4

 「あんたがフォロー記事を書けばいいじゃん」って言われればその通りなので、前に自分が書いた記事に触れておくことにしました。

PerlPerl以外でファイルのやりとりをする可能性はないのでしょうか

人間には文字化けして見える「繝輔ぃ繧、繝ォ.txt」というファイル名だって、Windowsにとっては(そしてPerlにとっても)正常なファイル名ですもの。warningを出す理由がありませんでしょ。Perlの中で閉じているかそうでないかの差でしょう

 人間以外も認識できないと思いますけれど。

 Perlが扱うUTF8文字列なファイル名はWindows(あるいはそこで動くアプリケーション/ツール)にとっての「正常な」ファイル名ではありません*5。少なくともPerl以外のアプリケーション/ツールで作った「ファイル.txt」はお互いに開けます*6Perlでは開けませんし、逆もまたしかりです*7

 あるいは逆に、printした結果が「繝輔ぃ繧、繝ォ」であっても、それは人間には文字化けして見えるだけですから、warningを出す必要はないんじゃないでしょうか*8

 ファイル名は「Perlで閉じている」ものではないのですから、ファイルの中身と同様に扱うのが自然だと思うのです。

僕はファイル名も文字列として扱いたいわけですよ

 ファイル名は常にバイト列でしかあり得ない、というのであればd:id:charsbarさんの主張も(ある程度は)理解できますが、僕は文字列として扱いたいのですよ*9

 例えば、正規表現でマッチさせるとか、(encodingを問わない)テキストファイルからファイル名を読み込んで(あるいは加工なりなんなりして)処理するとかね。

歴史は繰り返す、のかな

でもね、お作法というなら、UTF8フラグ付きの文字列として扱う前にはdecodeをするのがお作法。ファイルシステム含め外部とのやりとりをするときはencodeするのもお作法。ファイル名を文字列として扱いたいってのとは話が別

 うん、それはそうです。

 でもね、UTF8文字列をprint(あるいはreadline)するときはbinmode(やopenの引数等)で自動的に変換するように指定できるじゃないですか*10。あるいはprint時にencodeを指定しないとwarningが出るじゃないですか*11

 ファイル名を扱うときも同様にしたほうが仕様としては統一感があるでしょ、ということです。Practicalだと言うんであれば、そうであったほうが実用的にも便利ですし。

 ファイル名を実行環境に合わせてPerl側が全自動でなんとかしろ、なんて話はしていなくて*12、printなんかと同様にUTF8文字列をファイル名として使った時は指定したencodeで変換すればいいのにね、どうしてそうなっていないんだろう、って話なんですよ。仕様として不思議だなというのはそういうこと。

 printの時と同様に勝手にUTF-8バイト列(オクテット)として出力するんじゃない、するんであればwarningくらい出したほうがいいんじゃね、と。5.8.0あたりの事を思い出しますと、特にね。

 この辺の仕様の疑問については(昔Encodeがらみのメールのやりとりがあったのもあって)Jcodeメーリングリストにも

1. open()などでUTF8文字列をファイル名に使った時はwarningを出すべきではないか
 print等での扱いを考えると、open等でもwarningを出したほうが良いと思うのですが、
いかがでしょうか。

2. UTF8文字列をファイル名に指定した時、できれば自動的にencodeして欲しい
 encodingのようなプラグマで指定するか、あるいは3引数openの2番目の引数
で指定できるのが望ましいように思います。

――みたいな形で提案(あるいは質問)をしてはいたのです。

*1:および補足

*2:もっとも、そもそもマルチバイトなファイル名については何も考慮していないんじゃないか――少なくとも何かを検討したうえで現在の仕様に決めたわけではなくて、たまたま現在こうなっているだけ――という気もしますけれど。

*3:ちなみに僕は「浅倉」であって「朝倉」ではありません。念のため。

*4:ちょうどその手の事について考えていたタイミングだったものですから。

*5:「ちゃんと扱えない」と思っているのはそのためです。「いちおう扱える」とは思いますけれど。ま、その辺はPerlに限った話じゃないですが。

*6:ついでにファイル名で検索もできます。

*7:これはWin32以外でも同じで(おそらくd:id:charsbarさんの指摘通り)LOCALE等によって変わったりするんじゃないのかな。そもそもマルチバイトなファイル名について考慮されていないOSのほうが多いかもしれませんが。

*8:ところで、UTF8フラグ付きでprintする方法はないと思いますが(UTF8フラグはperlの内部情報だから)、何かやり方があるんでしょうか。少なくともUTF8で書かれたファイルを読み込んでも勝手にUTF8フラグを付けて読み込んだりはしないはずです。

*9Perlでマルチバイトを含めた文字列を扱う時は、UTF8フラグ付きの文字列として扱うのが標準的な作法です。

*10:「ちゃんと使える」のはこういう機能があるから。

*11UTF-8で出力するときも明示しなくちゃ駄目ですし。

*12:まあできるんであれば対応したほうが嬉しいとは思うけれど。