perl5.8のエンコードで悩んでいます。
5.6環境下でjcodeなどを使用したいろいろな処理は普通にできるのですが、そろそろ5.8での文字処理もちゃんとできないとあぶないかなと思い、練習していましたが…なんとも挙動が解らないときがあります…。
よければご教授いただけると幸いです。
まず基本的な練習として、POSTされた文字データを受領するものを作ってみました。
<<送信元 post1.html>>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dt …
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<p>POST実験</p>
<form id="form1" method="get" action="post2.cgi">
<p>data1 <input name="data1" type="text" /> </p>
<p>data2 <input name="data2" type="text" /> </p>
<p> <input type="submit" name="button" value="送信" /> </p>
</form>
</body>
</html>
<<受領部 post2.cgi>>
#!/usr/bin/perl
#モジュール利用宣言
use CGI; #CGIモジュール
use strict; #表記の正規化を強制
use warnings; #警告表示
use CGI::Carp qw(fatalsToBrowser); #エラー報告有効
#エンコーディングの指定
#use utf8; #この部分を有効にすると入力内容が文字化け
#use encoding 'UTF-8';#これも同様に入力内容が文字化け
#データの受領と変数名整理
my $input_data = new CGI;
my $in_data1 = $input_data->param('data1');
my $in_data2 = $input_data->param('data2');
#入力チェック
my $message_data = ""; #変数初期化
if($in_data1 eq "" && $in_data2 eq ""){$message_data = "入力部に空欄があります";}
else{$message_data = 'Data1は'.$in_data1.'Data2は'.$in_data2.'です';}
#ヘッダ発行
print "Content-type: text/html\n\n";
#html表示
print <<END_OF_HTML;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<p>サシスセソはSJISで化けるカタカナ。<br>入力内容は${message_data}</p>
</body></html>
END_OF_HTML
exit;
両ファイルともTeraPadを利用して、文字コードはUTF-8N、改行はLFにしています。
しかし、use utf8;と書くと、入力文字が化けてしまいます。
(コメントアウトすると普通に表示されます)
ちょっと漠然としていて申し訳ないのですが、なぜ化けるんでしょう…。
いろいろ調べてみたんですが、binmode STDOUT, ":encoding(utf-8)";とかをつけても特に変化がありません…。
しかし変わりすぎてキツい…でも今は5.8仕様の文字処理ができないとあぶないのかなぁ…。
A 回答 (3件)
- 最新から表示
- 回答順に表示
No.3
- 回答日時:
> ↓はPOSTされ、CGI.pmで受領したデータを、現在のperlスクリプトが使用するutf8形式にデコードする。
と考えてよろしいでしょうか?> my $in_data1 = Encode::decode('utf8', $input_data->param('data1')); #変更
意味合いとしては、utf8の文字列を内部形式(uft8)にデコードしてます。
しかし実際には、UTF-8フラグが付くだけです。
私も前に答えたときは確信がなかったので言いませんでしたが、
文字化けする原因は$in_data1や$in_data2にUTF-8フラグが付いていないことです。
たとえば、以下のコードのようにわざとUTF-8フラグを落とすと
最後のprintで出力されたテキストはutf8としても読めないものになってしまいます。
#-----------------------------------------------------------#
use strict;
use utf8;
use open ":utf8";
use open ":std"; #標準入出力にutf8を指定。
my $data="こんにちは"; #use utf8してるのでUTF-8フラグが付いている
utf8::encode($data); #わざとUTF8フラグを落とす
#↑は$data = Encode::encode('utf8',$data); と同じ。
print $data; #正しく出力されない
# UTF8フラグが落ちてるので、出力時に$dataの内容がLatin 1と見なされて
# 強引にUTF8に変換(upgrade)されてしまい文字化けする。
#-----------------------------------------------------------#
あなたが最初に提示しているコードの場合、
文字化けはUTF8フラグが立っている文字列と
UTF8フラグが立っていない文字列を連結したときに起こっています。
このときもUTF8フラグが立っていない文字列がupgradeされるので
文字化けしてしまいます。
Encode::decode('utf8', $data); はutf8をutf8(内部形式)に変換しており一見無意味なようですが、
この処理をしないとperlは$dataがutf8だと言うことが分かりません。
なのでちゃんと教えてあげないと、perlは不適切なupgradeをしてしまうのです。
[参考]
Perl 5.8 以降においての Unicode 文字列の扱い方 : NDO::Weblog
http://naoya.dyndns.org/~naoya/mt/archives/00061 …
Perl 5.8.x Unicode関連
http://www.rwds.net/kuroita/program/Perl_unicode …
> もし元の文字コードがわからなかったら
Encode::Guessなどで推測は可能ですが、
推測は失敗することもあります。
普通は送り側も自分で書きますから
送られてくる文字コードが不明と言うことは普通はないのではないかと思います。
> binmode(STDIN,":encoding(sjis)") ;
ブラウザはgetやpostでデータを送るときに
「%A4%B3%A4%F3%A4%CB%A4%C1%A4%CF」のようにエンコードしてから送るので、
たとえ漢字やひらがなを送ったとしても実際に送られてくるのはASCII文字だけです。
(CGI.pmが元に戻しているので気づいていないかもしれませんが。)
なのでエンコード指定は無意味なきがします。
あと、postの場合はSTDINからデータが得られますが、
getの場合は環境変数から取得するのでSTDINのモードを変更しても影響ないでしょう。
No.2
- 回答日時:
問題があると言ったけど、
CGI.pmはデコードまで責任を持たないと考えれば
これはこれで良い気もしてきた。
もし、post1.htmlをEUC-JPで書いた場合は、
#--------------------------------------------------
my $in_data1 = Encode::decode('euc-jp', $input_data->param('data1'));
my $in_data2 = Encode::decode('euc-jp', $input_data->param('data2'));
#--------------------------------------------------
とする必要があるわけだし、
内部コードに変換するために必ずこれが必要になったと思えば良いのかな。
No.1
- 回答日時:
どうやら、CGI.pmの実装に問題があるようですね。
(私も基本的にuse utf8してますが、
CGI.pm使わずにpostデータを解析してるのでこの問題は今初めて知りました。)
とりあえず以下のような変更をすればちゃんと表示されると思います。
#--------------------------------------------------
use utf8;
use Encode; #追加
my $input_data = new CGI;
my $in_data1 = Encode::decode('utf8', $input_data->param('data1')); #変更
my $in_data2 = Encode::decode('utf8', $input_data->param('data2')); #変更
#--------------------------------------------------
#参考
CGI.pmとUTF8 flag : blog.nomadscafe.jp
http://blog.nomadscafe.jp/archives/000491.html
ご指摘のように修正しましたら、ちゃんと動くようになりました。
バグではないとは言え、CGI.pmに起因する問題だったのですね。
ありがとうございます。
できましたら少しばかり追加質問なのですが…、
↓はPOSTされ、CGI.pmで受領したデータを、現在のperlスクリプトが使用するutf8形式にデコードする。と考えてよろしいでしょうか?
my $in_data1 = Encode::decode('utf8', $input_data->param('data1')); #変更
(…もし元の文字コードがわからなかったら…いやでも最近はhtml側でもキャラセット指定が入るし、大丈夫なのかな)
と言うことはつまり、perl5.8で「use utf8;」を使用するということは、スクリプトファイル自体の文字コードを宣言することと同時に、スクリプトが動作するときに、どのような文字コード体系で文字を扱うかを指定する…と考えても良いのかな…。
従来は特に指示しない場合、スクリプトファイル自体の文字コードで処理していたと思うのですが…しっかり指定しないといけないのか…。
ちなみに携帯とかではSJISを使うことになりますが、この場合は下のようになるのでしょうか?
use utf8;
binmode(STDIN,":encoding(sjis)") ;
binmode(STDOUT,":encoding(sjis)") ;
…でも、調べてみるとbinmodeはファイルの取り扱いについて指定するとあるので、POSTデータには作用しないのかな…。いやそもそもCGI.pmを使う以上、ご指摘いただいたように全データをデコード、エンコードし直す…ことになるのかな…。
ううむ…むずかしい…。ちょっと今はスクリプトに触れないのですが、後日自分でも試してみます。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- PHP PHPでCookieを使った訪問回数について 1 2023/05/28 14:10
- CGI perlで書いたcgiでsqliteの使い方を教えてください 2 2023/05/08 21:29
- HTML・CSS 私の能力からして間違っていないような気がします。 4 2022/09/30 13:24
- PHP PHPでユーザー情報を入力して簡易ログイン機能をつくってみたのですが 1 2023/05/29 08:51
- CGI htmlからパラメータで、cgiに渡したい。 1 2023/02/06 16:15
- PHP PHPのエラーの解消法について教えて下さい。 1 2023/02/06 10:48
- PHP 入力した部分を表示させたまま(保持)するにはどうすれば良いでしょうか? 1 2023/01/25 11:14
- JavaScript switch文のswitch(n)の部分を複数の値にするか、if文に変えてほしいです。 1 2022/07/27 17:18
- AJAX JavascriptからPHPへのAjax通信でnullが返ってくる 3 2022/08/03 22:00
- JavaScript jQueryでのドラッグアンドドロップについて 1 2022/07/07 21:04
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
CGIでメール送信で件名文字化け
-
MFCのコントロールにUTF-8の文...
-
perl でエラー:Wide character...
-
perlについての質問
-
CSVファイルの中で、「 , 」カ...
-
エクセルで数値を全角文字(カ...
-
EXCELからCSVにすると余計なカ...
-
VBA 置換文字がみつからない時
-
マクロを使ってフォルダー内に...
-
VBA EXCEL あるセルの中の一...
-
「何とかで始まり、何とかで終...
-
pythonエラー
-
データにカンマが入ったCSVデー...
-
全角入力
-
英数字のみ全角から半角に変換
-
パイソンエラーについて
-
word差し込み印刷 半角カタカ...
-
[VBA][Excel]クリップボードか...
-
CString から LPCTSTRの型に変換
-
VBA 文字に半角が含まれて...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
perl でエラー:Wide character...
-
【LaTeX】pBibTeXでのエラーの...
-
【文字コード】外見上は全く同...
-
MFCのコントロールにUTF-8の文...
-
perlについての質問
-
sedやperlでの2バイト文字を含...
-
WindowsでUTF-8のPerlスクリプ...
-
HTML::Templateでutf-8のテンプ...
-
Java+MySQLで特殊文字(丸数字(...
-
jcode.plのかわり
-
UTF-8のPerlから、UTF-8、EUC、...
-
CGIでメール送信で件名文字化け
-
Perlで、文字の出現回数を調べ...
-
perlで読み込むテキストの文字...
-
UTF-16からUTF-8への変換
-
Jcodeによるカタカナ→ひらがな変換
-
PIC16F84AのBlank Checkは
-
printfの書式指定での2バイト文...
-
JcodeモジュールとEncodeモジュ...
-
perl について
おすすめ情報