解決済みの質問
今まで全てのPerlをjcode.plを使って日本語化してきました。
長年根本の構造をきちんと理解せず、jcode.plは呪文のように最初に宣言して使用してきたため、現在文字化け対策をするため、今回Encodeモジュールを使って日本語変換を行うための方法が分からず困っています。
formから送信されてきたものを変換するため、
foreach $pair(@pairs) {
($name,$value) = split(/=/,$pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
$name =~ tr/+/ /;
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
&jcode'convert(*name,'sjis');
&jcode'convert(*value,'sjis');
$in{$name} = $value;#ここは状況に応じて変えてます
}
として最初に一括して変換してやり、
ウェブ上で表示させるときは
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
を指定してそのまま表示、
メールなどでは
&jis("Subject: $sub"); print AAA "$msg\n";
sub jis { $msg = $_[0]; &jcode'convert(*msg, 'jis'); }
などとして出力してきました。
これらをEncodeモジュールを使って書き換えたいのですが、参考に
http://digit.que.ne.jp/work/wiki.cgi?Perl%E3%83%A1%E3%83%A2%2F%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%81%AE%E6%89%B1%E3%81%84
このページを読んだのですが、perlの根本が理解できていないので、どこをどうしていいのか分かりません。
上のような形式をEncodeモジュールを使って書き換えるとすればどのようにすればいいのでしょうか。
(どう聞けばいいかも分からないので、うまく伝えられたか不安ですが)
投稿日時 - 2010-02-27 18:25:57
#1です
ああ、その書き方では駄目です。
Base64 エンコードする必要があるのはあくまでも日本語などの『非ASCIIのデータ』のみですから
&jis("$sub"); &base64("$msg"); print AAA "Subject: $str\n";
となります("Subject:"の部分はエンコードしちゃ駄目)
ですから正確を期すならば sub base64 も
sub base64 {
use MIME::Base64;
$str = $_[0];
if($str =~ /[^!-~\s]/){
$str = encode_base64($str, "");
$str = '=?iso-2022-jp?B?' . $str . '?=';
}
}
としておけば完璧でしょう(サブジェクトにASCII以外の文字が含まれている場合のみ Base64 エンコードを行います)
return $str; に関して
コメントアウトしないと動作しないとの事ですが…
そうですね。その関数の呼び出し方だとそうなるかもしれません。
最初見た時は何気に見過ごしていたのですが、今回改めて眺めてみて
&jis("Subject: $sub"); &base64("$msg"); print AAA "$str\n";
この一行の意味がしばらく理解できなかったです。何故?何故変数名がコロコロ変わってるの??この変数はどっから湧いてきた???って
strict モジュールを用いて必ず変数宣言する癖がついて幾星霜。こんなperl4チックなスクリプトは久しぶりだったもので油断しました。
とりあえず今回の質問とは全然関係ないのでスルーしても良いのですが、今後も perl を触り続けるのならば、上記のようなソースは NG となりますので、一度キチンと基本から学んでおいた方が良いかもしれませんよ?(大きなお世話ですが)
興味があるようでしたら、 use strict みたいなワードでグーグル先生に聞いてみましょう。
PS
print AAA "Content-Type: text/plain\; charset=\"ISO-2022-JP\"\n\n\n";
↑改行しすぎでコーヒー吹いた
改行は2個で良いんですよ、2個で↓
print AAA "Content-Type: text/plain\; charset=\"ISO-2022-JP\"\n\n";
投稿日時 - 2010-03-02 20:36:53
お礼
ありがとうございました
無事正常に稼働するようになりました。
>何故?何故変数名がコロコロ変わってるの??この変数はどっから湧いてきた???って
>strict モジュールを用いて必ず変数宣言する癖がついて幾星霜。
perlを最初に触ったときは、フリーのスクリプトを紙に起こし、それを睨めっこして覚えました。
もちろんプラスして入門書も使いましたが、小難しいことは書いてません。
そのため本当の基本が分かってないので$_とかといったいわゆる「それ」という使い方が難しく、確実に”その”データを取るため、こうやっています
foreachとかも@データを各行ループさせるときにもわざわざ毎回固有変数名をつけてやってたりします
格好悪いですし、myとかの使い方もよく分かってないため、長いスクリプトになるとかえってわけ分からなくなるので、何とか直したいのですが・・・入門をネットで探したらあまりにも入門過ぎるし、それ以上を探すと自分のレベルを遙か超えた内容ばかりでなかなか次のステップへ上がるための本やサイトが見つからなくて困ってます
>use strict みたいなワードでグーグル先生に聞いてみましょう
ありがとうございます。
どこでどう学んでいいのか分からないので、この文字を参考に引いてます
>改行は2個で良いんですよ、2個で
何個いるのか理由もさっぱり分かっておりません
このコードはもう何年前になるでしょうか。
10年以上前だったか、perlを初めて触ったときに参考にしたスクリプトを意味も分からずそのまま使ってましたので
投稿日時 - 2010-03-03 15:55:25
3人が「このQ&Aが役に立った」と投票しています
ベストアンサー以外の回答(3件中 1~3件目)
#1です
>ここのEncodeの中の$valueは$strでいいのでしょうか?
>$subject2を$subとすればいいのでしょうか?
おっしゃる通りでございます。
なんかいろいろとグダグダで申し訳ありません。
んでパールの記述チェックで Prototype mismatch エラーが出たということは、多分 encode って名前のサブルーチンがすでにスクリプト内で宣言されているのではないでしょうか?( sub encode でスクリプトを検索してみてください)Encode モジュールを使用するならばこの名前は使用できませんので、別の名前に置換してやる必要があります。
ちなみに、
>文字化けすることがたびたびある
との事ですが、別にこれは jcode.pl に原因があるわけではなく、スクリプトの書き方に問題が在るためだと思いますよ(多分ですけど)
文字コードを変換するときに incode をキッチリと明示してやればそうそう化ける事などない筈です。
というかそもそも
・フォームを記述した html が Shift_JIS
・スクリプトも Shift_JIS
・スクリプトが吐き出すデータも Shift_JIS
ならば文字コードを変換する必要がそもそも無くなるわけで、論理的に文字化けなど起こる筈もありません(機種依存文字や携帯の絵文字を使われたらその限りではありませんが、これはもうどうしようもないですもん)
まぁそれでも『今更 jcode.pl なんか使ってらんねぇぜ!俺は Encode を使いたいんだYO!』という気持ちも解らないでもありません。そんな場合は Jcode.pm を Encode モジュールのラッパーとして使用するのが一番簡単かもしれないですね(今更そんな事言うなよ!という突っ込みはナシの方向で…)
jcode.pl と同じ感覚で Encode モジュールを使用する事が可能です。
作業その1
require './jcode.pl'; を require './Jcode.pm'; に変更
作業その2
スクリプト内の &jcode' を &Jcode:: に全置換
作業その3
Jcode.pmをサーバにアップ
基本的にこれだけで作業は完了です。
詳しくは Encode モジュールの作者であり、 Jcode モジュールの作者でもある小飼 弾様のサイトを参照なさってみてください。
参考URL:http://openlab.ring.gr.jp/Jcode/index-j.html
投稿日時 - 2010-03-02 01:34:20
お礼
非常に丁寧な解説本当にありがとうございます。
試行錯誤しながらもなんとか少しずつ前に進んでいる・・・と思います。
Prototype mismatchの件はおっしゃるズバリのとおりでしたので即解決できました。
それと、
sub jis {
$str = $_[0];
Encode::from_to($value, "shiftjis", "iso-2022-jp");
return $str;
}
は、うまくいかなかったのですが、最後のreturn $str;を#を加えて実質非稼働にしてみたらうまく作動しました。
あとちょっとだけ教えて頂きたいのですが。
日本語変換のおまけで教えて頂いたbase64です。
&jis("Subject: $sub"); &base64("$msg"); print AAA "$str\n";
sub jis {
$msg = $_[0];
Encode::from_to($msg, "shiftjis", "iso-2022-jp");
}
sub base64 {
use MIME::Base64;
$str = $_[0];
$str = encode_base64($str, "");
$str = '=?iso-2022-jp?B?' . $str . '?=';
}
iso-2022-jpに変換したあとbase64に変換しなくてはならないとのことでしたが、上記のようにしてみたところ、
&jis("Subject: $sub"); &base64("$msg"); print AAA "$str\n";
の後ろにヘッダーの続きとして記述してあった
print AAA "Content-Transfer-Encoding: 7bit\n";
print AAA "Content-Type: text/plain\; charset=\"ISO-2022-JP\"\n\n\n";
をひっくるめてメールのbody内に書込まれてしまいました。
sub base64内の最後に
return $str;
を書き加えてみても動作は同じでした
(なぜかsub jis内ではreturn $msg;を加えるとエラーになるのにこちらではなりませんでした)
このiso-2022-jpとbase64への変換の連続技はどのようにしてやればうまくいくのでしょうか。
PS Jcode.pmの件もありがとうございました。ここまで進めてきたので今回はEncodeでやり遂げたいと思いますが、Jcode.pmもあわせて勉強してみたいと思います。
投稿日時 - 2010-03-02 11:58:31
文字化け対策で何故 Encode モジュールを使用するのでしょう?
よくわからないなぁ…?
ユニコードでも扱うとでもいうのでしょうか?
想像で恐縮ですが、ここでは UTF-8 で作成されたフォームからデータを受け取りたいのだと仮定しておきます。
まずは最初におまじないを記述
use Encode qw(from_to encode);
あとは
foreach $pair(@pairs) {
($name,$value) = split(/=/,$pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
$name =~ tr/+/ /;
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
Encode::from_to($name, "utf8", "cp932");
Encode::from_to($value, "utf8", "cp932");
$in{$name} = $value;
}
これでとりあえず受け取ったデータを Shift_JIS に変換できました。
(正確には CP932 ですけどね。Shift_JIS に変換せても良いけど Unicode => Shift_JIS の変換には色々と問題があるので無難に CP932 をチョイスしました)
Encode にも受け取ったデータを自動で判別する機能は存在しますが、精度があんまりよろしくないのでそれこそ文字化けの原因になります。ですんで例のようにキチンと incode を明示してやる事を激しく推奨です。
メールなどで ISO-2022-JP に変換したいのならば、サブルーチン jis を
sub jis {
$str = $_[0];
Encode::from_to($value, "shiftjis", "iso-2022-jp");
return $str;
}
こんな感じで良いと思うのですが…
ちなみにメールのヘッダ内で使用する日本語は上記のルーチンだけでは不正な書式になります。
ISO-2022-JP に変換した後にBASE64エンコードしてやる必要があります。
で、一応 BASE64 エンコードするサブルーチンの例も記述
sub base64 {
$str = $_[0];
$str = encode_base64($str, "");
$str = '=?iso-2022-jp?B?' . $subject2 . '?=';
return $str;
}
投稿日時 - 2010-03-01 00:08:53
お礼
記述例まで書いて頂き、ありがとうございます。
>文字化け対策で何故 Encode モジュールを使用するのでしょう?
>よくわからないなぁ…?
文字化けすることがたびたびあるので対策方法を探しておりましたらjcode.plは古いから使わない方がいいというページがわんさか出てきたので、サーバーもperlが5.8なのでならば日本語化にはEncodeを使うほうがいのかなぁ・・・と、ただそれだけの理由です。
目的は、入力されたもの送信するもの全てが、できる限り(できることなら全く)文字化けしないようにしたいのです。
とくにEncodeにこだわってはいません。
早速教えて頂いた内容を元にやってみました。
追加でお尋ねしたいのですが、
$str = $_[0];
Encode::from_to($value, "shiftjis", "iso-2022-jp");
return $str;
ここのEncodeの中の$valueは$strでいいのでしょうか?
$str = '=?iso-2022-jp?B?' . $subject2 . '?=';
の部分ですが、質問に書いた形ですと$subject2を$subとすればいいのでしょうか?
あとパールの記述チェックをしたところ
Prototype mismatch: sub main::encode ($$;$) vs none at test.cgi line 181.
test.cgi syntax OK
とでてきました
エラーの場所は、エラーに表示されたラインから推測して
$msg = $_[0];
Encode::from_to($msg, "shiftjis", "iso-2022-jp");
retern $msg;
のところだと思います。
これはどう解決すればいいのでしょうか。
ネットでももちろん調べてみたのですが、どう解決していいのか分かりません
サーバーのperlバージョンは5.8.*です
投稿日時 - 2010-03-01 16:14:04