Perlで日本語を含むフォルダ名の扱いで苦労した話
はじめに
Windows 11のXAMPP上で動くCGIプログラム(Perl)で日本語を含むフォルダ名の扱いに苦労した話。 分かってしまえばなんてことはないんだけど。
環境
> C:\xampp\perl\bin\perl.exe -v This is perl 5, version 32, subversion 1 (v5.32.1) built for MSWin32-x64-multi-thread
また、フォルダ階層が以下のようになっている。
> ls C:\xampp\日本語を含むフォルダ\ ディレクトリ: C:\xampp\日本語を含むフォルダ Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2024/07/13 9:28 012345 d----- 2024/07/13 9:28 abcde d----- 2024/07/13 9:28 あいうえお d----- 2024/07/13 9:28 かきくけこ
現象
CGIプログラムとしてではなく、単体で動かしたときも同様なので、後者で動かすプログラムとして書いていく。
use utf8; use File::Find; my $path = qw(C:\xampp\日本語を含むフォルダ); if (-e $path) { print "OK\n"; } else { print "NG\n"; } sub _process { print $File::Find::name . "\n"; if (-e $File::Find::name) { print "OK\n"; } else { print "NG\n"; } } find(\&_process, $path);
これを実行すると、失敗する。
NG Wide character in warn at C:/xampp/perl/lib/Carp.pm line 293. Can't stat C:\xampp\譌・譛ャ隱槭r蜷ォ繧繝輔か繝ォ繝: No such file or directory at .\test1.pl line 19.
対策1(間違い)
あぁ、内部文字列か、ということで、以下のように書き換えた。
use utf8; use Encode; use File::Find; my $path = qw(C:\xampp\日本語を含むフォルダ); $path = Encode::encode('Shift_JIS', $path); if (-e $path) { print "OK\n"; } else { print "NG\n"; } sub _process { print Encode::encode('Shift_JIS', $File::Find::name) . "\n"; if (-e Encode::encode('Shift_JIS', $File::Find::name)) { print "OK\n"; } else { print "NG\n"; } } find(\&_process, $path);
実行する。
OK C:\xampp\???{?????????t?H???_ NG C:\xampp\???{?????????t?H???_/012345 NG C:\xampp\???{?????????t?H???_/abcde NG C:\xampp\???{?????????t?H???_/???¢?????¨ NG C:\xampp\???{?????????t?H???_/?????????± NG
・・あれ?
対策2(正解)
いろいろと検証して以下にたどり着く。
use utf8; use Encode; use File::Find; my $path = qw(C:\xampp\日本語を含むフォルダ); $path = Encode::encode('Shift_JIS', $path); if (-e $path) { print "OK\n"; } else { print "NG\n"; } sub _process { print $File::Find::name . "\n"; if (-e $File::Find::name) { print "OK\n"; } else { print "NG\n"; } } find(\&_process, $path);
実行結果。
OK C:\xampp\日本語を含むフォルダ OK C:\xampp\日本語を含むフォルダ/012345 OK C:\xampp\日本語を含むフォルダ/abcde OK C:\xampp\日本語を含むフォルダ/あいうえお OK C:\xampp\日本語を含むフォルダ/かきくけこ OK
そりゃあそうですよね、と。
ソースコードにべた書きされたパスは「UTF-8」から変換された「内部文字列」なので、フォルダの存在確認などをする際には「Shift_JIS」にエンコードしてやる必要があるが、フォルダを読み込んで得られるパス名に関しては「もともとShift_JIS」なので、それを変換するとおかしなことになるのは当たり前。
30分くらいにらめっこしていました。