【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード

いつもお世話になっております。

以下の例の様に
文字コードがEUCであるか正規表現で判定ロジックを記述したいのですが、
どのように記述すればよろしいのでしょうか?

(例)
if(文字コードがEUCであるか正規表現でチェック){
 処理A
}

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% …

元の文字列を取得するには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;
-------------------------------------------------------------------

参考URL:http://www.din.or.jp/~ohzaki/perl.htm#JP_Escape

この回答への補足

ご連絡ありがとうございます。
すごく助かります。

文字コードの判定処理をする前に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
  で、デコードした文字を取得しようとしています)

以上です。
よろしくお願い致します。

補足日時:2009/04/01 18:14
    • good
    • 0

確かに %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;
-------------------------------------------------------------------

参考URL:http://www.kt.rim.or.jp/~kbk/perl-5.8/guess.html
    • good
    • 0
この回答へのお礼

ご連絡ありがとうございます。
長々とお付き合い頂きありがとうございます。
大変助かりました。

他に聞きたい事がありますが、
とりあえずこの質問はCLOSEさせて頂きます。

ありがとうございました。

お礼日時:2009/04/08 11:49

単にUTF-16エンコーディングという場合は、BOM付きか、BOM無しのビッグエンディアンとなるようです。


http://ja.wikipedia.org/wiki/UTF-16#UTF-16.E7.AC …
ですので、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;

補足日時:2009/04/07 14:32
    • good
    • 0

前出の正規表現とpack関数の処理では %uXXXX に対応していません。


URI::Escape も %uXXXX に対応していないみたいですね。(そもそも %uXXXX は規格外?)
%uXXXX に対応している URI::Escape::XS というモジュールも在るようです。
http://blog.livedoor.jp/dankogai/archives/508189 …
ただし、標準モジュールではなさそうですのでインストールが必要になります。

正規表現と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;

補足日時:2009/04/07 11:28
    • good
    • 0

特に正規表現を直接使って書く必要が無いのでしたら、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に載っています。

参考URL:http://www.din.or.jp/~ohzaki/perl.htm#JP_Code

この回答への補足

ご連絡ありがとうございます。
基本的な事をご質問させて下さい。

以下のプログラムで、文字コードを出力すると「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;

補足日時:2009/04/01 15:10
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!