- ベストアンサー
文字コードの変換(Shift-JISからUTF8)
- 文字コードがShift-JISのCSVファイルを読み込み、UTF-8のテキストファイルに出力する際の文字コード変換について解説します。
- プログラムの中で文字コードを変更しようとしているが、うまくいかないという状況について質問しました。
- 使用しているツールやモジュール、コードの一部を記載し、解決策を求めています。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
あの、私のや他の回答をよく読んで考えてください。 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 $_; } この部分は **** $_には何の影響も与えません **** よって、** 出力に関することだけに注目したら ** for(my $i=0;$i<@data;$i++){ print OUT $_; } これと等価です。どこで「Shift_JIS からUTF-8へ変換」してますか? $_は「while (<IN>){」の<IN>で1行読み込まれ、「chomp ($_);」で末尾の改行コードが削除されただけで、移行なにも変化していません。コードは入力のまま=Shift_JISです。それをそのまま出力すればShift_JISになるのが正解です。 しかも、項目数分だけ繰り返し出力されます。 (重複行になる、と#1に書いたのはchompのことを失念していた私のミスです) @dataを変更したのなら、出力するのは@dataでしょう。 join(",", @data)とすれば、項目をカンマ区切りの文字列にすることができます。 あと#2にあったfrom_toの使い方。マニュアルをよく読みましょう http://perldoc.perl.org/Encode.html#[$length-=]-from_to($octets,-FROM_ENC,-TO_ENC-[,-CHECK]) ・$octetsを直接変換する ・$octetsの長さを返す とあります。つまり $data[$i]=Encode::from_to($data[$i],'shiftjis','utf8') だと,$data[$i]には元の内容は破棄されて、文字列の長さになってしまいます。 各項目毎に処理したい、という意図はわかりました。 ですが、文字コードの変換が項目毎に違うなんてことはまず無いでしょう。 それならば、$_で1行をコード変換→splitして項目毎の処理、としてもいいのでは? ついでにPerlIOを使って open (IN, "<:encoding(shift_jis)", $input_file) or die "$!"; open (OUT, ">:utf8", $output_file) or die "$!"; とでもやれば、プログラム中はコードをあまり意識せずに文字列処理ができます。
その他の回答 (4)
- kabaokaba
- ベストアンサー率51% (724/1416)
んーー・・・読めない人なのかねー 本質的に以下と同じことをしてるって指摘されてるんだけどなー $a=1; $b = $a + 1; print $a; ## $aに1を足してるのになぜか 1 って表示されるっ!? もしかして,@dataを$_のリファレンスみたいなものだと思ってる? #nkfとかiconvを使う方がいいかもね.
- _--_1l1_1_
- ベストアンサー率67% (102/152)
もう一度 2 つの回答をよく読んだら。
- Tacosan
- ベストアンサー率23% (3656/15482)
#1 で何を言われたのか理解できているんでしょうか? このプログラムは入力をほぼそのまま出力しています. つまり, 「文字コードがShift-JISのCSVファイルを読み込」んだら「出力ファイルの文字コードを確認するとShift-JISのまま」なのは当然です. むしろ, このプログラムでなぜ「UTF-8のテキストファイルに出力する」と思ったのでしょうか? 実際のプログラムが (特に出力の部分で) こうなっていないというなら, 実際のプログラム (に近いもの) を出してください. あと, 「文字コードの変換方法」について勘違いしている. Encode::from_to の使い方を確認してください.
補足
Tacosanさん 回答ありがとうございます。 質問したプログラムは単に文字コードがShift-JISである入力ファイルを文字コードがUTF-8である出力ファイルに変換するプログラムを作成したいだけです。 私が考えたのは下の箇所で 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 $_; } (別に1行ずつencodeすればよかったですが、) Shift-JISのデータをUTF-8のデータに変換でき、UTF-8の出力ファイルに格納できると 思っていましたができませんでした。 何かいいやりかたはありますか?
- kmee
- ベストアンサー率55% (1857/3366)
> my @data=split(/,/,$_); で$_を分割して新しく作った@dataに対して処理しているのですから @dataを変更しても $_には影響ありません。 ・現状、同じ行が複数出力されていませんか?1行の項目数分、$_の出力を繰り返すのですから。 ・そもそもsplitする意味はあるのでしょうか?
補足
kmeeさん いろいろ不備があり、すいません。このプログラムの目的はカンマ区切りになっている項目をそれぞれ抽出し、いろいろ手を加えたいと思っているため、そうなっています。その部分はうまくいっていて、今は文字コードの部分だけがうまくいかない状況です。 言葉足らずですいませんでした。
お礼
kmeeさん 詳しい親切な回答ありがとうございます。 勉強になりました。 Encode:from_toについて書いてあった何人かのHPを読んでいて 同じ使い方をやっていたとのそれを鵜呑みにしてしようしていました。 これからはPerldocを参考にしたいと思います。 本当にありがとうございました。