• ベストアンサー

guess_encoding()の挙動が意味不明

Wernerの回答

  • Werner
  • ベストアンサー率53% (395/735)
回答No.1

○うまくいかない直接の原因 > foreach my $j (@data) { >   $j=$decoder->decode($j); >   $j=encode('utf-8', $j); >   print "$j<br>\n"; > } ここで@dataを書き換えてしまっているので、 2回目以降のdecodeが全て失敗しているのだと思います。 なぜ、@dataが書き換わるのか分からなければ、以下のスクリプトを試して見れば分かります。 #--ここから-- my @data = (0,1,2,3,4,5,6,7,8,9); print join(",", @data) . "\n"; #=> 0,1,2,3,4,5,6,7,8,9 foreach my $j (@data) {  $j = $j + 10; } print join(",", @data) . "\n"; #=> 10,11,12,13,14,15,16,17,18,19 #--ここまで-- ○他の余り良くない点 > foreach my $j (@data) { >  $decoder=guess_encoding($j,$i); >  $check=0 unless ref($decoder); > } データを細切れにしてguess_encodingに渡すのは 判定精度が落ちるので良くありません。 guess_encodingには出来るだけ多くのデータを、 例えば今回の場合はファイルの内容を全て渡した方が良いでしょう。 もっとも、このコードだと1行でもguess出来なければ失敗としているので 精度に関しては問題ないかもしれません。 しかし、ループする分処理効率が落ちますし、 あまり良いことはないと思います。 また、guess_encodingの第二引数には、エンコーディング名のリストを渡せるので @all_encodingsを渡してしまって良いと思います。 #----------Sample---------- use utf8; #このスクリプトはUTF-8で記述されている。 use strict; use warnings; use Encode; use Encode::Guess; binmode(STDOUT, ":utf8"); # STDOUTに出力するとき、PerlIOレイヤで透過的にUTF-8に変換 # 全てのエンコード名取得 my @all_encodings = Encode->encodings(":all"); # BOMが必要な文字コードを除外 @all_encodings = grep {$_ ne "UTF-16" and $_ ne "UTF-32"} @all_encodings; # ファイルの内容を全て$dataに格納 my $fname="shift-JIS.txt"; open(my $in, "<", $fname); my $data = do {local $/ = undef; <$in> }; close($in); # 文字コードを判定 my $guess = guess_encoding($data, @all_encodings); my @guess_list = ref $guess ? ($guess->name) : split(" or ", $guess); # UTF-8で出力 foreach my $enc_name (@guess_list) {  my $decoder = find_encoding($enc_name);  my $decoded_data = $decoder->decode($data);  $decoded_data =~ s/\n/<br>\n/g;  print "[$enc_name]<br>\n";  print $decoded_data;  print "\n"; }

makoji
質問者

補足

わざわざサンプルプログラムまで組んでくださってありがとうございます。 短いプログラムにも関わらず、私が知らないコードが幾つか入っていて、昨日からフォローのために本を読んだり、とても勉強になりました。 zxcv0000さんも指摘されていますが、ファイルを細切れにするのは問題があるとは思っていました。スマートなファイルダンプの方法を知らなかったので、とりあえず後回しにしていたのですが、知っている方が書かれると、とても簡単ですね。 同じ文字化けが何度も出てきたのでとまどってしまいました。確かにファイルデータを取り込んだ@dataを最初のループで書き換えてしまうと、2回目以降は元のファイルデータで処理を行うことが出来ませんね。これはEncode.pmがどうこう以前のバグです。失礼いたしました。 ちょっと分からないのが、前回私のプログラムを作動させた際に、@dataに最初の書き込みを行った文字コードはcp1006であるようですが、この時Perlは@dataをcp1006で書かれていると判断してそれをutf8に変換しています。その次にcp1025で同様な作業をしているわけですが、一旦utf8に変換したデータをcp1025と判定してもう一度utf8に再変換をかけることになりますから、@dataは  $decoder=guess_encoding($j,$i); が、「この文字コードが使われています」と判断する度に書き換えられて違う値を取るようになってしまうのではないでしょうか。 毎回同じ文字化けを起こしてしまうのは何故なのでしょう。

関連するQ&A

  • デコード処理について

    いつもお世話になっております。 Perlのデコード処理で分からない事があります。 大変申し訳ございませんが、 ご存知の方がいらっしゃれば、教えて頂けますでしょうか。 以下のプログラムを実施すると以下のエラーが発生しまい 正しくデコードされた結果が表示されません。 この場合、どのようにして$sの文字をUTF-8と判断させて shiftjisに変換すればよいのでしょうか? (プログラム) #!/usr/local/bin/perl use Encode qw/from_to/; use Encode::Guess; Encode::Guess->set_suspects(qw/shift-jis euc-jp 7bit-jis/); $s = '%E7%A7%BB%E8%BB%A2'; # UTF-8 $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; (エラー内容) shiftjis or euc-jp or utf8 at test.pl line 12.

  • WWW::Mechanizeの文字コードについて質問

    WWW::Mechanizeの文字コードについて質問 以下のようなソースコードを書いて実行してみたのですが どのサイトを取得しても、すべて文字コードがUTF8だと認識されます。 ------------------------------------------------------- #!/usr/bin/perl #WWW:MechanizeでHTMLの取得 use WWW::Mechanize; $w = WWW::Mechanize->new(); $w->get("URL"); $html=$w->content; #文字コードの判別 use Encode; use Encode::Guess qw/ascii utf8 euc-jp shiftjis 7bit-jis/; my $dec = Encode::Guess->guess($html); print$dec->name; ------------------------------------------------------- 例えば以下のサイトは文字コードがEUC-JPですがこれもprintされるのはUTF8となってしまいます。 http://barukanlog.blog31.fc2.com/blog-entry-541.html WWW:Mechanizeでサイトを取得し、サイトの文字コードを調べてすべてsjisにする ということがしたいのですが、すべてutf8に判断されて先へ進めないんです。 何か設定やメソッドを追加しなくてはいけないのでしょうか? わかりにくい質問かとは思いますがご回答お願いします。

  • Perl 文字コードについて

    From: $from To: $mailto CC: $mailcc Subject: $subject Mime-Version: 1.0 Content-type: text/plain;charset=\"UTF-8\" Content-Transfer-Encoding: 8bit この時点で、UTF-8を指定しました。 use Encode; use Encode::Guess; Encode::Guess->set_suspects( qw/ euc-jp shiftjis 7bit-jis / ); $name = encode('UTF-8', decode('Guess', $name)); で本文を、UTF-8に変換して送るようなコードを書きました。 これで一応、パソコン、スマホ共に「本文」は文字化けせず送れるのですが、 今度、別の問題が発生してしまったようで、 「件名」が文字化けしてしまうようになりました。 $subject = encode('UTF-8', decode('cp932', $subject)); 件名も、本文と同じように変換コードをしてみたところ、パソコンでは文字化けしませんでしたが「件名」で文字化けしてしまいます。 調べたところ本文と件名では、内容が違い MIMEエンコードを使用するとのことだったのですが、 実際どのように使うのかわからないです。 $subject = encode('ISO-2022-JP', decode('cp932', $subject)); encode('MIME-Header-ISO_2022_JP', $subject) このように記述するとスマホでは文字化けしないのですが パソコンで文字化けしてしまいます。 そこで、件名がパソコンとスマホで文字化けしないようにし、本文はUTF-8で送るようにするにはどのようにすればいいのでしょうか?

    • ベストアンサー
    • Perl
  • JcodeモジュールとEncodeモジュール

    以下、Perl5.8でJcodeモジュールを使った場合とEncodeモジュールを使った場合の違いについて、知りたいです。 ※そもそもこのモジュールは同時に使ったらだめなのでしょうか? use strict; use utf8; use Jcode; use Encode; my $dat1 = "あイ卯(1)Iⅰ"; Jcode::convert(\$dat1, "utf8"); my $dat2 = "あイ卯(1)Iⅰ"; $dat2 = Encode::encode("utf8", $dat2); 文字コード変換の正しい使い方が知りたいです。

    • ベストアンサー
    • Perl
  • Encode と encoding の同時使用で ISO-2022-JP に encode できない

    CentOS を 5.1 から 5.2 にアップデートした頃から PerlCGI からのメール送信が出来なくなって、調べていたら「ISO-2022-JP への encode がおかいぞ問題」に辿り着きました。 以下のコードで、euc-jp が吐かれてしまいます。 #! /usr/bin/perl -w use encoding('UTF8'); use Encode; binmode(STDOUT); my $text = "<全角文字ですよぉ。>"; print encode('ISO-2022-JP', $text), "\n"; 以下のいずれかで正常に jisコードを吐く様になるのですが、こんなものなんでしょうか? 1 「use encoding('UTF8');」 を 「use utf8;」に替える 2 print の直前に "no encoding;" を入れる CentOS 5.1 では多分正常に ISO-2022-JP への変換ができていたのだと思います。 私の使用するバージョンの Cygwin の Perl でも正常です。 問題のある CentOS5.2 と 問題の無い Cygwin版で、関係しそうなバージョンの違いはありません。 CentOS 5.2: Perl 5.008008 Encode 2.12 Encode::JP 2.01 encoding 2.02 Cygwin: CYGWIN_NT-5.1 **** 1.5.25(0.156/4/2) 2008-04-17 12:11 i686 Cygwin Perl 5.008008 Encode 2.12 Encode::JP 2.01 encoding 2.02 できれば、すでに動いているCGIの use encoding('UTF8'); を直す事なく動く様にしたいのです。

  • 文字コードの変換(Shift-JISからUTF8)

    文字コードがShift-JISのCSVファイルを読み込み、UTF-8のテキストファイルに出力するのに プログラムの中で変更しようとしているのですが、うまくいきません。出力ファイルの文字コードを 確認するとShift-JISのままです。 どなたか教えていただけないでしょうか? ActivePerl v5.16.0を使用し、Encodeモジュールのfrom_toを使用しています。 #!/usr/bin/perl use strict; use warnings; use utf8; use Encode; my $input_file="input.csv"; my $output_file="output.txt"; open (IN, $input_file) or die "$!"; open (OUT, ">$output_file") or die "$!"; while (<IN>){ chomp ($_); my @data=split(/,/,$_); for(my $i=0;$i<@data;$i++){ $data[$i]=Encode::from_to($data[$i],'shiftjis','utf8'); #Shift-JISからUTF-8に変換 $data[$i]=~s/\s+//g; print OUT $_; } print OUT "\n"; } close (IN); close (OUT);

    • ベストアンサー
    • Perl
  • Perlの文字コード変換についての質問です。

    Perlの文字コード変換についての質問です。 ホームページ全体は、UTF-8で作成されています。 そのため、$qsは、どうも、S-JISのようなので、UTF-8に変換して URLデコードさせたいのですがうまくいきません。 文字化けしないで、UTF-8で作成されたページに表示させたいのですがどうすればよいでしょうか? 宜しくお願い致します。 ------------------------------------ $qs = $ENV{'QUERY_STRING'}; use Encode::Guess qw/ shiftjis /; use Encode qw/ decode /; $enc = guess_encoding ( $qs ); if ( ref $enc ) { $utf8 = decode ( $enc->name , $qs ); } $qs =~ tr/+/ /; $qs =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('H2', $1)/eg; print "$qs";

    • ベストアンサー
    • Perl
  • Encodeについて

    いつもお世話になっております。 下記の構文で分からないところがございます。 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行は、文字コードを推測して、そのあとが分かりません。 いつも初心者質問で申し訳ありませんが、よろしくお願いいたします。

  • [Perl]Shift-JISのXMLを解析する場

    行き詰まってしまったので教えて下さい。 <やりたいこと> とあるAPIからXMLファイルを取得し、解析して出力する、ということをやっているのですが、元のXMLがShift-JISでエンコーディングされており、これをUTF-8に変換して出力しようとしています。 <問題> XMLを取得して解析、取り出したいパラメータが出力できるようにはなったのですが、文字のエンコーディングが上手く行っていないためか、文字化けしてしまいます。 <元のXML> <?xml version="1.0" encoding="Shift_JIS"?>  <test>   <prod count=3>    <record>     <code>アイウエ</code>    </record>    <record>     <code>カキクケ-</code>    </record>    <record>     <code>ABC</code>    </record>   </prod>  </test> <XML解析用のコード> #!usr/bin/perl use utf8; use Encode qw/ from_to encode decode /; use Encode::Guess qw/ euc-jp shiftjis 7bit-jis /; use LWP::UserAgent; use XML::Simple; use Data::Dumper; #--XML取得部分省略 #--XMLはgetで$xmlに格納 $from = guess_encoding($xml)->name; &from_to($xml,$from,"utf8"); $XML::Simple::PREFFERRED_PARSER = 'XML::SAX::PurePerl'; $xs = new XML::Simple(); $ref = $xs->XMLin($xml); $xml =~ s/<\?.*\?>//; for($i=0;$i<=$#{$ref->{'test'}->{'prod'}->{'record'}};$i++){  $name = $ref->{'test'}->{'prod'}->{'record'}[$i]->{'code'}; $name = encode('utf-8',$name); print "$i : $name\n"; } <結果> 黒ダイヤに?文字で文字化けして出力される。 どなたか原因がお分かりになりますでしょうか。 よろしくお願いいたします。

  • UTF-8で書かれたHTMLファイルをShift-JISのファイルに変換できない

    #!/usr/bin/perl -w =begin comment OS: Windows XP Perl: Active Perl v5.8.8 スクリプトは「Shift-JIS」で書いています。 日本語処理関係で参考にしているのはもっぱらオライリージャパンの「Spidering Hacks」の付録の翻訳者 による日本語処理の解説です。 http://oshiete1.goo.ne.jp/qa3716434.html の回答に従い、use encoding 'shiftjis'; から use encoding 'cp932'; へ変更している以外は そこに書かれているやり方に従っていると思います。 UTF-8で書かれたHTMLファイルを「LWP::UserAgent」で取得し、それを Shift-JISコードで出力したいと思い以下のコードを実行したのですが、 以下のエラーが出てしまいました。 Parsing of undecoded UTF-8 will give garbage when decoding entities at C:/usr/local/site/lib/LWP/Protocol.pm line 114. このエラーは何が原因なのでしょうか? =end comment =cut use strict; use LWP 5.64; use Encode; use encoding 'cp932'; # http://oshiete1.goo.ne.jp/qa3716434.html の回答に従い、'shiftjis'から'cp932'へ変更。 #use encoding 'shiftjis'; binmode(STDERR, ':raw :encoding(shiftjis)'); my $url = "http://www.audiounion.jp/bin/products/used/A0/-/-/"; my $browser = LWP::UserAgent->new; my $response = $browser->get( $url ); die "cannot get $url:", $response->status_line unless $response->is_success; my $content = Encode::decode('utf8', $response->content); print $content;