プロが教えるわが家の防犯対策術!

いつもお世話になっております。
下記の構文で分からないところがございます。
use Encode;
use Encode::Guess qw/euc-jp shiftjis 7bit-jis/;
use Encode qw/decode/;
$enc=guess_encoding($x);
if(ref $enc){$x=decode($enc->name,$x);}

実はあるテキストに載っていたコードなのですが、解説には
文字データのコードが分からない場合は、Encode::Guessを使います
としか書いてありません。
2行目は、文字コードのリストをqwで囲んであると分かりますが
3行目は、なぜdecodeをqwで囲む必要があるのでしょうか。
decodeメソッドを使うと意味だとすると、必要ないように思ってしまい
ました。大きな勘違いをしているかもしれません。
最後の2行は、文字コードを推測して、そのあとが分かりません。
いつも初心者質問で申し訳ありませんが、よろしくお願いいたします。

A 回答 (2件)

まず情報の訂正から。


> Encode::decode とか Encode::encode のように修飾した名前を使わなければならないところで
> decode や encode のように記述できるようになります。

と書きましたが、Encodeの場合はちょっと事情が複雑でした。

use Encode; とした場合
Encode::decode のような修飾なしで関数を呼び出せる。

use Encode qw(decode); とした場合
qw()の中に書かれた関数は修飾なしで呼び出せるが、
それ以外の関数は修飾した名前でないとエラーになる。
つまり上の例の場合、
deocde(ほげほげ)→OK
encode(ほげほげ)→NG
Encode::encode(ほげほげ)→OK
のようになります。

わたしが良く見るモジュールでは前回書いたように、
qw で後に並べた名前だけ修飾なしで使えるというものがほとんどだったと思います。



次に、#1の補足にある
> 結果は
> こんにちは
> shiftjis or utf8
>でした。
geuss_encodingがこれを返したということは、
shiftjis か utf8 のどちらかだと思われるが情報が少なくて決定できない。
ということです。
Encode::Guess によるエンコーディングの判定は
Jcodeのものよりもより汎用的にできているため、
データが少ない場合の推測結果があまり正確でなかったり、
今回のように決定できないということになったりします。
もし日本語のエンコーディングだけ推測できればいい
ということであれば、Jcodeを使ったほうが自動判定は成績が良い傾向にあります。


http://blog.livedoor.jp/dankogai/archives/507373 …

あたりにちょっと事情が載っています。

対策としてはできるだけ長い文字列を与えて判定させるようにするくらいですかねえ。
    • good
    • 0
この回答へのお礼

sakusaker7さん、アドバイスありがとうございました。
文字列が少ないと判別に失敗したり、複数行ある場合、1行ずつ
異なるコードと判定したりするようですね。
推測(guess)できなかったときの処理をきちんとしておく必要が
あるという結論でしょうか。
Encodeについては、以前にもこのサイトで質問させて頂きました。
私自身は、HTML担当でPerlは勉強中です。文字化け対策としては
HTMLも、Perlプログラムも全てutf-8で保存する、コンテントタイプ
ヘッダで宣言もするというのが一番の解決と思っています。
それでも化けることがあると聞いたことがありますが・・・
もっと勉強しないとスキルアップできませんね。
お忙しいところ誠にありがとうございました。

お礼日時:2007/12/21 09:43

> 3行目は、なぜdecodeをqwで囲む必要があるのでしょうか。


> decodeメソッドを使うと意味だとすると、必要ないように思ってしまい
> ました。大きな勘違いをしているかもしれません。

ためしに、
> use Encode qw/decode/;
のqw/decode/ の部分を削除して実行してみてください。

> if(ref $enc){$x=decode($enc->name,$x);}
の部分で、mainパッケージにdecodeなんて関数ないよという
感じのエラーになるはずです。
つまり、use Encode の後ろにリストで関数名を渡しておくと、
本来なら
Encode::decode とか Encode::encode のように修飾した名前を使わなければならないところで
decode や encode のように記述できるようになります。

> 最後の2行は、文字コードを推測して、そのあとが分かりません。
> $enc=guess_encoding($x);
> if(ref $enc){$x=decode($enc->name,$x);}

guess_encodeingが返しているのは、推測によって得られたエンコーディングの情報です。
そして、$enc->name は何かというと、その結果のエンコーディング名です。
つまり、'euc-jp' とか 'utf-8' のようなものです。
ですのでdecodeの第一引数として渡すことができるわけです。

また、ref $enc のようなチェックをしているのは、
適当なエンコーディングに決められなかった場合に、guess_encodingの戻り値は
リファレンスではないので、それによりdecode可能かどうかを判定しているためです。
#Encode::Encodingのオブジェクトじゃなかったかなあ。
ですので、decodeのところはオブジェクトのそれを活かして
if(ref $enc){$x = $enc->decode($x);}
でも同じ結果になったと思います。

この回答への補足

こんにちは。質問者です。
やっと実験できました。下記のように書いてアップロードしてみました。
結果は
 こんにちは
 shiftjis or utf8
でした。

use Encode qw/decode/; → これは、なくても動いたようです。
でも内容については、実際にいろいろ試してみて
やっと分かってきました。
お騒がせして申し訳ありません。ありがとうございました。

use Encode;
use Encode::Guess qw/euc-jp shiftjis 7bit-jis/;
my $x="こんにちは";
my $enc=guess_encoding($x);
if(ref $enc){$x=decode($enc->name,$x);}
print <<END;
Content-type: text/html; charset=utf-8

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">

<title>サンプル</title>
</head>
<body>
<p>$x</p>
<p>$enc</p>
</body>
</html>
END

補足日時:2007/12/20 01:28
    • good
    • 0
この回答へのお礼

sakusaker7様
丁寧な答ありがとうございます。
decodeメソッド、encodeメソッドは、use Encode;
と記述すれば使えるのではないかと思っていました。
例えば
use Encode;
my $data="shift_jisで書かれた文字列";
$data=decode("shift_jis",$data);
$data=encode("utf-8",$data);
というような場合とは異なるということでしょうか。
ダブルコロンは、以前
use CGI;
$CGI::POST_MAX=1024;
で使用したことがありますが、こっちは理由がよく分かりました。
今回の場合は、「?」だったのです。
中途半端なコメントで申し訳ありません。
睡魔のため頭が働かないので、また明日改めてコメントします。

お礼日時:2007/12/18 02:25

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