- ベストアンサー
文字コードの判定処理について
いつもお世話になっております。 以下の例の様に 文字コードがEUCであるか正規表現で判定ロジックを記述したいのですが、 どのように記述すればよろしいのでしょうか? (例) if(文字コードがEUCであるか正規表現でチェック){ 処理A }
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
> $s='%B5%D9%BB%DF%A1%A6%B2%F2%CC%F3%A1%A6%C9%FC%B3%E8'; この文字列には、%とアルファベットと数字しか存在しませんので、ASCII文字しか含まれていません。 これは、URLエスケープされたデータですね。 http://ja.wikipedia.org/wiki/URL%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%89 元の文字列を取得するにはURLアンエスケープしてやる必要が有ります。 URLアンエスケープするには、URI::Escape モジュールを使うか、正規表現とpack関数で「%XX」をバイトデータに変換します。 例) URI::Escape モジュールを使う場合 ------------------------------ use Jcode; use URI::Escape; my $str = '%B5%D9%BB%DF%A1%A6%B2%F2%CC%F3%A1%A6%C9%FC%B3%E8'; my $unescape_str = uri_unescape($str); my ($code, $nmatch) = getcode($unescape_str); print $code; ------------------------------------------------------------------- 例) 正規表現とpack関数を使う場合 ---------------------------------- use Jcode; my $str = '%B5%D9%BB%DF%A1%A6%B2%F2%CC%F3%A1%A6%C9%FC%B3%E8'; $str =~ tr/+/ /; $str =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('H2', $1)/eg; my ($code, $nmatch) = getcode($str); print $code; -------------------------------------------------------------------
その他の回答 (4)
- root139
- ベストアンサー率60% (488/809)
確かに %uXXXX の有無で処理を分ける必要は有りそうですね。 %uXXXX の有無で Encode::Guess の候補を切替える方法でも大丈夫そうです。 例) --------------------------------------------------------------- use Encode qw/from_to/; use Encode::Guess; $hikisu = $ARGV[0]; if ($hikisu == 1) { $s = '%u4f11%u6b62%u30fb%u89e3%u7d04%u30fb%u5fa9%u6d3b'; # UTF-16 } elsif ($hikisu == 2) { $s = '%E4%BC%91%E6%AD%A2%E3%83%BB%E8%A7%A3%E7%B4%84%E3%83%BB%E5%BE%A9%E6%B4%BB'; # UTF-8 } elsif ($hikisu == 3) { $s='%B5%D9%BB%DF%A1%A6%B2%F2%CC%F3%A1%A6%C9%FC%B3%E8'; #EUC } elsif ($hikisu == 4) { $s='%8Bx%8E%7E%81E%89%F0%96%F1%81E%95%9C%8A%88'; #SJIS } if ($s =~ /%u[0-9a-fA-F]{4}/) { Encode::Guess->set_suspects('utf-16be'); } else { Encode::Guess->set_suspects(qw/shift-jis euc-jp 7bit-jis/); } $s =~ tr/+/ /; $s =~ s/%(?:([0-9A-Fa-f]{2})|u([0-9A-Fa-f]{4}))/pack('H*', defined($1) ? $1 : $2)/eg; my $decoder = Encode::Guess->guess($s); die $decoder unless (ref($decoder)); &from_to( $s, $decoder->name, "shiftjis" ); print $s; -------------------------------------------------------------------
お礼
ご連絡ありがとうございます。 長々とお付き合い頂きありがとうございます。 大変助かりました。 他に聞きたい事がありますが、 とりあえずこの質問はCLOSEさせて頂きます。 ありがとうございました。
- root139
- ベストアンサー率60% (488/809)
単にUTF-16エンコーディングという場合は、BOM付きか、BOM無しのビッグエンディアンとなるようです。 http://ja.wikipedia.org/wiki/UTF-16#UTF-16.E7.AC.A6.E5.8F.B7.E5.8C.96.E3.82.B9.E3.82.AD.E3.83.BC.E3.83.A0 ですので、BOM無しの UTF-16LE は来ないものとして良ければ、Encode::Guess の判定対象から UTF-16LE を外してはどうでしょう? 例) --------------------------------------------------------------- use Encode qw/encode/; use Encode::Guess qw/shift-jis euc-jp 7bit-jis UTF-16BE/; $s='%u4f11%u6b62%u30fb%u89e3%u7d04%u30fb%u5fa9%u6d3b'; #UTF-16 $s =~ tr/+/ /; $s =~ s/%(?:([0-9A-Fa-f]{2})|u([0-9A-Fa-f]{4}))/pack('H*', defined($1) ? $1 : $2)/eg; my $decoder = Encode::Guess->guess($s); die $decoder unless (ref($decoder)); print $decoder->name; print " (UTF-16)" if ($decoder->name =~ /^UTF-16/i); print "\n"; my $utf8 = $decoder->decode($s); print encode("shift-jis", $utf8); -------------------------------------------------------------------
補足
ご連絡ありがとうございます。 教えて頂きましたプログラムだとうまく動作しました。 しかし、以下のプログラム(1)の様に1つのプログラムで実行すると 以下のような結果が表示されました。 なので、以下の案の方法で対応しようかと思います。 (プログラム(1)) #!/usr/local/bin/perl use Encode qw/from_to/; use Encode::Guess qw/shift-jis euc-jp 7bit-jis utf-16be/; $hikisu = $ARGV[0]; if($hikisu == 1){ $s = '%u4f11%u6b62%u30fb%u89e3%u7d04%u30fb%u5fa9%u6d3b'; # UTF-16 } elsif($hikisu == 2){ $s = '%E4%BC%91%E6%AD%A2%E3%83%BB%E8%A7%A3%E7%B4%84%E3%83%BB%E5%BE%A9%E6%B4%BB'; # UTF-8 } elsif($hikisu == 3){ $s='%B5%D9%BB%DF%A1%A6%B2%F2%CC%F3%A1%A6%C9%FC%B3%E8'; #EUC } elsif($hikisu == 4){ $s='%8Bx%8E%7E%81E%89%F0%96%F1%81E%95%9C%8A%88'; #SJIS } # UTF-16を含むエンコードデータか否かを識別 if($s =~ /%u[0-9a-fA-F]{4}/){ $s =~ tr/+/ /; $s =~ s/%(?:([0-9A-Fa-f]{2})|u([0-9A-Fa-f]{4}))/pack('H*', defined($1) ? $1 : $2)/eg; my $decoder = Encode::Guess->guess($s); die $decoder unless (ref($decoder)); &from_to( $s, $decoder->name, "shiftjis" ); } # UTF-8,EUC-JP,shiftjisも以下の処理でデコード処理を実施する。 else{ $s =~ tr/+/ /; $s =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("H2", $1)/eg; my $decoder = Encode::Guess->guess($s); die $decoder unless (ref($decoder)); &from_to( $s, $decoder->name, "shiftjis" ); } print $s; (結果) 1.引数に1を設定した場合 休止・解約・復活 2.引数に2を設定した場合 UTF-16BE or utf8 at test_090325_16_2.pl line 36. 3.引数に3を設定した場合 euc-jp or UTF-16BE at test_090325_16_2.pl line 36. 4.引数に4を設定した場合 shiftjis or UTF-16BE at test_090325_16_2.pl line 36. (案) #!/usr/local/bin/perl use Encode qw/from_to/; use Encode::Guess qw/shift-jis euc-jp 7bit-jis/; $hikisu = $ARGV[0]; if($hikisu == 1){ $s = '%u4f11%u6b62%u30fb%u89e3%u7d04%u30fb%u5fa9%u6d3b'; # UTF-16 } elsif($hikisu == 2){ $s = '%E4%BC%91%E6%AD%A2%E3%83%BB%E8%A7%A3%E7%B4%84%E3%83%BB%E5%BE%A9%E6%B4%BB'; # UTF-8 } elsif($hikisu == 3){ $s='%B5%D9%BB%DF%A1%A6%B2%F2%CC%F3%A1%A6%C9%FC%B3%E8'; #EUC } elsif($hikisu == 4){ $s='%8Bx%8E%7E%81E%89%F0%96%F1%81E%95%9C%8A%88'; #SJIS } # UTF-16を含むエンコードデータか否かを識別 if($s =~ /%u[0-9a-fA-F]{4}/){ $s =~ tr/+/ /; $s =~ s/%(?:([0-9A-Fa-f]{2})|u([0-9A-Fa-f]{4}))/pack('H*', defined($1) ? $1 : $2)/eg; &from_to( $s, "utf-16be", "shiftjis" ); } # UTF-8,EUC-JP,shiftjisも以下の処理でデコード処理を実施する。 else{ $s =~ tr/+/ /; $s =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("H2", $1)/eg; my $decoder = Encode::Guess->guess($s); die $decoder unless (ref($decoder)); &from_to( $s, $decoder->name, "shiftjis" ); } print $s;
- root139
- ベストアンサー率60% (488/809)
前出の正規表現とpack関数の処理では %uXXXX に対応していません。 URI::Escape も %uXXXX に対応していないみたいですね。(そもそも %uXXXX は規格外?) %uXXXX に対応している URI::Escape::XS というモジュールも在るようです。 http://blog.livedoor.jp/dankogai/archives/50818918.html ただし、標準モジュールではなさそうですのでインストールが必要になります。 正規表現とpack関数を使う場合は、置換処理を下記の様にしてやれば良さそうです。 ------------------------------------------------------------------- $s =~ s/%(?:([0-9A-Fa-f]{2})|u([0-9A-Fa-f]{4}))/pack('H*', defined($1) ? $1 : $2)/eg; ------------------------------------------------------------------- 上記のどちらかの方法で、%uXXXX 形式のエスケープに対応できると思います。 判定の方ですが、対象のエンコーディングに UTF-16BE, UTF-16LE を加えるたらどうでしょう? 手元に Encode::Guess が動く環境が無いので、確認はしていません。 例) --------------------------------------------------------------- use Encode::Guess qw/shift-jis euc-jp 7bit-jis UTF-16BE UTF-16LE/; $s='%u4f11%u6b62%u30fb%u89e3%u7d04%u30fb%u5fa9%u6d3b'; #UTF-16 $s =~ tr/+/ /; $s =~ s/%(?:([0-9A-Fa-f]{2})|u([0-9A-Fa-f]{4}))/pack('H*', defined($1) ? $1 : $2)/eg; // この時点で$sにはデコードされた文字列が入っている。(2)のご質問。 my $decoder = Encode::Guess->guess($s); die $decoder unless (ref($decoder)); print $s; -------------------------------------------------------------------
補足
ご連絡が遅くなり大変申し訳ございません。 ご連絡頂きましたプログラム1を実施したところ、 「die $decoder unless (ref($decoder));」の個所で 「UTF-16BE or UTF-16LE at test_090325_16_3.pl line 10.」とエラーが発生しました。 とりあえず、shift-jisで文字を表示したかったので、 プログラム2を実施したところ正しく文字が表示されました。 (但し、&from_to( $s, "utf-16le", "shiftjis" )で実施すると文字化けのままでした。) utf-16be/utf-16leを気にせずにshiftjisに変換する方法は ありますでしょうか? 度々のご質問で大変申し訳ございませんが、 よろしくお願い致します。 (プログラム1) use Encode::Guess qw/shift-jis euc-jp 7bit-jis UTF-16BE UTF-16LE/; $s='%u4f11%u6b62%u30fb%u89e3%u7d04%u30fb%u5fa9%u6d3b'; #UTF-16 $s =~ tr/+/ /; $s =~ s/%(?:([0-9A-Fa-f]{2})|u([0-9A-Fa-f]{4}))/pack('H*', defined($1) ? $1 : $2)/eg; my $decoder = Encode::Guess->guess($s); die $decoder unless (ref($decoder)); print $s; (プログラム2) #!/usr/local/bin/perl use Encode qw/from_to/; use Encode::Guess qw/shift-jis euc-jp 7bit-jis UTF-16BE UTF-16LE/; $s='%u4f11%u6b62%u30fb%u89e3%u7d04%u30fb%u5fa9%u6d3b'; #UTF-16 $s =~ tr/+/ /; $s =~ s/%(?:([0-9A-Fa-f]{2})|u([0-9A-Fa-f]{4}))/pack('H*', defined($1) ? $1 : $2)/eg; &from_to( $s, "utf-16be", "shiftjis" ); print $s;
- root139
- ベストアンサー率60% (488/809)
特に正規表現を直接使って書く必要が無いのでしたら、Encode::GuessやJcodeを使われるのが良いかと。 例) --------------------------------------------------------------- use Jcode; my ($code, $nmatch) = getcode($str); if ($code eq 'euc') { # EUCの場合の処理 } ------------------------------------------------------------------- 例) --------------------------------------------------------------- use Encode::Guess qw/shift-jis euc-jp 7bit-jis/; my $decoder = Encode::Guess->guess($str); die $decoder unless (ref($decoder)); if ($decoder->name eq 'euc-jp') { # EUCの場合の処理 } ------------------------------------------------------------------- 正規表現を使った日本語文字コードの判定ロジックは参考URLに載っています。
補足
ご連絡ありがとうございます。 基本的な事をご質問させて下さい。 以下のプログラムで、文字コードを出力すると「ascii」と表示されます。 一応文字コードはEUCなのでですが、教えて頂きましたプログラムを使用して EUCと表示する方法はあるのでしょうか? (プログラム) #!/usr/local/bin/perl use Jcode; $s='%B5%D9%BB%DF%A1%A6%B2%F2%CC%F3%A1%A6%C9%FC%B3%E8'; my ($code, $nmatch) = getcode($s); print $code;
補足
ご連絡ありがとうございます。 すごく助かります。 文字コードの判定処理をする前にURLアンエスケープするんですね。 おかげでshiftjis、UTF-8のURLエスケープされたデータも 文字コードの判定が出来ました。 度々で申し訳ございませんが、もう2点ご確認させて頂けますでしょうか。 (1)以下のプログラムを実施したところ文字コードが 「ascii」と表示されました。 文字コードを「UTF-16」と取得する為に、 何か別な方法はあるのでしょうか? (現状は、 if($s =~ /%u[0-9a-fA-F]{4}/){ で、「UTF-16」の判定処理をしようとしています) (プログラム) #!/usr/local/bin/perl use Encode::Guess qw/shift-jis euc-jp 7bit-jis/; $s='%u4f11%u6b62%u30fb%u89e3%u7d04%u30fb%u5fa9%u6d3b'; #UTF-16 $s =~ tr/+/ /; $s =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('H2', $1)/eg; my $decoder = Encode::Guess->guess($s); die $decoder unless (ref($decoder)); print $s; (2)'%u4f11%u6b62%u30fb%u89e3%u7d04%u30fb%u5fa9%u6d3b'から デコードされた文字を取得したいのですが、 何かよい方法はありますでしょうか? (現状は、 simaguni.pl で、デコードした文字を取得しようとしています) 以上です。 よろしくお願い致します。