小池啓仁 ヒロヒト応援ブログ By はてな

小池啓仁(コイケヒロヒト)の動画など。

小池啓仁 ヒロヒト応援ブログ By はてな

シフトJIS漢字のファイル名にマッチしてみる

Perlベストプラクティス
たとえば、./hoge配下に『テストソース.txt』というファイルがあったとします。
検索文字列『ソース』で、./hoge配下を検索して、このファイルにマッチさせるには、以下の感じです。

◆その1:コードはshiftjis、処理はshiftjis、標準入出力はshiftjis

#!/usr/bin/perl
use strict;
use warnings;

while (my $fileName = glob("./hoge/*")) {
    if ($fileName =~ /ソース/) {
        print "Match\n";
    }
    else {
        print "Unmatch\n";
    }
    print $fileName, "\n";
}

実行結果

C:\test>perl kanji00.pl
Unmatched [ in regex; marked by <-- HERE in m/メ[ <-- HERE ス/ at kanji00.pl line 6.

しかし、上記ではマッチしません。
というか、正規表現エラーになります。
これは、『ソース』の『ー』の第2バイトが『[』のコードになっているからです。
そして、閉じの『]』がないために正規表現エラーになるのです。
なので、『[』を普通の文字扱いするために、『ソース』を\Qと\Eで囲んでみます。

◆その2:コードはshiftjis、処理はshiftjis、標準入出力はshiftjis

#!/usr/bin/perl
use strict;
use warnings;

while (my $fileName = glob("./hoge/*")) {
    if ($fileName =~ /\Qソース\E/) {
        print "Match\n";
    }
    else {
        print "Unmatch\n";
    }
    print $fileName, "\n";
}

実行結果

C:\test>perl kanji01.pl
Unmatch
./hoge/テストソース.txt

しかし、上記ではマッチしません。
なぜかというと、 /\Qソース\E/は、\Qより先に『ソース』文字列が評価されるので、基本的に『[』をエスケープしたに過ぎません。
なので、一度『ソース』文字列を変数に格納してみます。

◆その3:コードはshiftjis、処理はshiftjis、標準入出力はshiftjis

#!/usr/bin/perl
use strict;
use warnings;

while (my $fileName = glob("./hoge/*")) {
    my $wk = "ソース";
    if ($fileName =~ /\Q$wk\E/) {
        print "Match\n";
    }
    else {
        print "Unmatch\n";
    }
    print $fileName, "\n";
}

実行結果

C:\test>perl kanji02x.pl
Unmatch
./hoge/テストソース.txt

しかし、上記ではマッチしません。
これは、『my $wk = "ソース";』で『ソ』の第2バイトがエスケープ文字『\』のコードになっているからです。
そして、『ソ』の第1バイトと『ー』の第1バイトがくっ付いてしまうのです。たぶん。
なので、変数展開しないようにシングルクォート『my $wk = 'ソース';』にしてみます。

◆その4:コードはshiftjis、処理はshiftjis、標準入出力はshiftjis

#!/usr/bin/perl
use strict;
use warnings;

while (my $fileName = glob("./hoge/*")) {
    my $wk = 'ソース';
    if ($fileName =~ /\Q$wk\E/) {
        print "Match\n";
    }
    else {
        print "Unmatch\n";
    }
    print $fileName, "\n";
}

実行結果

C:\test>perl kanji02.pl
Match
./hoge/テストソース.txt

今度は、上手く行きました。
ということで、シフトJIS漢字を扱うには大変なわけです。
なので、処理はUTF-8にして、コードと標準入出力をshiftjisにしてみます。

◆その5:コードはshiftjis、処理はUTF-8、標準入出力はshiftjis

#!/usr/bin/perl
use strict;
use warnings;
use Encode;

# 標準入出力をutf-8からshiftjisへエンコーディングする
use encoding 'shiftjis';

while (my $fileName = glob("./hoge/*")) {

    # $fileNameをshiftjisからutf-8へデコード
    $fileName = decode('shiftjis', $fileName);

    if ($fileName =~ /ソース/) {
        print "Match\n";
    }
    else {
        print "Unmatch\n";
    }
    print $fileName, "\n";
}

実行結果

C:\test>perl kanji03.pl
Match
./hoge/テストソース.txt

今度も、上手く行きました。
しかし、WINDOWSでの漢字処理は、コードも処理もUTF-8にして、標準入出力をshiftjisが推奨らしい。
なので、スクリプトコードをUTF-8にして・・・。

◆その6:コードはUTF-8、処理はUTF-8、標準入出力はshiftjis

#!/usr/bin/perl
use strict;
use warnings;
use Encode;

# スクリプトの文字コードがutf-8であることの明示
use utf8;

# 標準出力をshiftjisでエンコーディング
binmode STDOUT, ':encoding(shiftjis)'; 

while (my $fileName = glob("./hoge/*")) {

    # $fileNameをshiftjisからutf-8へデコード
    $fileName = decode('shiftjis', $fileName);
    if ($fileName =~ /ソース/) {
        print "Match\n";
    }
    else {
        print "Unmatch\n";
    }
    print $fileName, "\n";
}

実行結果

C:\test>perl kanji04.pl
Match
./hoge/テストソース.txt

そう、これが正解みたいですね・・・。


詳説 正規表現 第3版

詳説 正規表現 第3版