プロが教える店舗&オフィスのセキュリティ対策術

お世話になっております。
フォームから入力された文字を、
「半角カタカナ→全角カタカナ」変換したいのですがうまくいきません。
コーディングは以下の通りですが、問題の箇所がわかりません。
どなたかご教授ください。
なお、jcode.plは、最新のものを使っています。


#↓===============================================

##### フォームデータ受け取り
if ($ENV{'REQUEST_METHOD'} eq 'POST') {
 read( STDIN , $buffer , $ENV{'CONTENT_LENGTH'} );
} else {
 $buffer = $ENV{'QUERY_STRING'};
}

# 文字コードを正確に取得するために,全ての送信データをいったん文字コードチェックする
$buffer1 = $buffer;
$buffer1 =~ s/%([0-9a-fA-F][0-9a-fA-F])/pack("C", hex($1))/eg;
$kcode = &jcode::getcode(*buffer1);

@pairs = split(/&/ , $buffer);
##### フォームデータのデコード、漢字コードをsjisに変換
foreach $pair (@pairs) {
 ($k,$v) = split(/=/,$pair);
 $v =~ tr/+/ /;
 $v =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
 &jcode'convert(*v,"sjis",$kcode);

 # 半角カナを全角に変換
 if($kcode eq 'sjis') {
  &jcode::h2z_sjis(\$v);
 }
 if($kcode eq 'euc') {
  &jcode::h2z_euc(\$v);
 }
 if($kcode eq 'jis') {
  &jcode::h2z_jis(\$v);
 }

 $in{$k} = $v;
}

#↑===============================================
(なお、全角スペースは、半角スペースなどに変更願います。)

よろしくお願いします。

A 回答 (8件)

文字量が少ないと文字コードの判別が正確にできないので、既に回答があったように文字量を増やす工夫が必要だと思います。



半角カナが混じっても判別精度を上げる方法が下記サイトに記述されてます。
参考にされるといいと思います。

Perlメモ
http://www.din.or.jp/~ohzaki/perl.htm#JP_Code

jcode.plはかなり古いライブラリーで、今から新しく書くスクリプトではあまりお薦めできません。以下のような変遷をたどっています。

jcode.pl → Jcode.pm → Encode.pm

今は、Encode.pmを使って文字列をUnicode化して使うのが主流です。
ちょっと難しいかもしれませんが、チャレンジしてみてください。

Encode::Guess -- データからエンコーディングを推測する
http://www.kt.rim.or.jp/~kbk/perl-5.8/guess.html

Perl で半角カナと全角カナの変換をする
http://www.serendip.ws/archives/2185


以下、参考コードを書いてみました。

use Encode 'from_to';
use Encode::JP::H2Z;

my $v = 'アイウエオ';
print $v, ' -> ';

my $enc = getcode($v);
die '文字コードが取得できませんでした' if $enc =~ /or/;

from_to($v, $enc, 'euc-jp');
Encode::JP::H2Z::h2z(\$v);
from_to($v, 'euc-jp', $enc);

print $v;

sub getcode {
my $str = shift;

my $ascii = '[\x00-\x7F]';
my $re_sjis_c = '[\201-\237\340-\374][\100-\176\200-\374]';
my $re_sjis_kana = '[\241-\337]';

my $re_euc_c = '[\241-\376][\241-\376]';
my $re_euc_kana = '\216[\241-\337]';
my $re_euc_0212 = '\217[\241-\376][\241-\376]';

require Encode::Guess;

my $enc = Encode::Guess::guess_encoding($str, qw/euc-jp shiftjis 7bit-jis/);
return $enc->name if ref $enc;

if( $enc =~ /shiftjis/ and $enc =~ /euc-jp/ ) {
if( $str !~ /^(?:$re_euc_c|$re_euc_kana|$re_euc_0212|$ascii)*$/o ) {
if( $str =~ /^(?:$re_sjis_c|$re_sjis_kana|$ascii)*$/o ) {
return 'shiftjis';
}
}
return 'euc-jp';
}

return $enc;
}
    • good
    • 0
この回答へのお礼

ご回答、誠にありがとうございます。

半角カタカナを全角カタカナに変換するのが、簡単にできないとは知りませんでした。
私のような初心者には、難易度が高すぎるようです。
出直した方がよさそうです。
今回の皆様のご回答は、必ず、役立たせたいと思います。
ありがとうございました。

お礼日時:2010/11/15 13:28

> 半角のアを入力した場合、$kcode=  (値なし)


> 半角のアイを入力した場合、$kcode=euc
> 全角のアを入力した場合、$kcode=sjis
> 全角のアイを入力した場合、$kcode=sjis

何事もなかったかのように書いてますけど、これが問題だと思わなかったのですか?
Shift_JISで入力しているのですから、この4つ全て「sjis」になるのが、期待している結果ですよね?
それが値なしや「euc」になるってことは、判定に失敗しているってことですよね?

最初の結果は、
Shift_JIS半角カナだけの入力→$kcode='euc'と誤判定→そのままconvertでEUCからSJISへ変換→当然コード不一致で文字化け
となったものです。

後の「正しく動いた」と言ってる方も
Shift_JIS半角カナだけの入力→$kcode='euc'と誤判定→if( $kcode eq 'euc' )が成立→ h2z_sjisを実行:EUCの場合の処理のはずなのに、SJISのh2zを使っている→元がShift_JISなので、h2z_sjisが期待通りに動作→「正しく動いた」ように見える

と、けっして「正しい動作」ではありません。
実際、本当にEUCで入力があって、正しく判定されたとすると
EUCの入力→$kcode='euc'と正しく判定→if( $kcode eq 'euc' )が成立→ h2z_sjisを実行→元がEUCなのでなので、h2z_sjisでは誤動作→カタカナばかりの変な出力
となります。

> 半角カタカナ1文字が入った場合、及び、半角カタカナとそれ以外の文字が混在する場合に、正しい結果(半角カタカナ→全角カタカナ変換)が得られません

それは、正しくsjisと判定されたときに、なんの処理もしていないからです。


convertの位置がおかしい(→h2zの処理の後にconvertする)なくらいで、最初のプログラムでやりかたは大体あってます。

問題なのは、$kcodeが実際のコードと違うことがある、ということ。
特に、Shift_JISの半角カナはEUCと誤判定されやすい、ということ。
jcode.pl だけでの対策は不可能。#6さんが例示したような「正しく判定されるしくみ」を入れる必要があります。
    • good
    • 0

http://mikeneko.creator.club.ne.jp/~lab/kcode/jc …
リンクに jcode の解説がありますので、読んでみてください。半角カナに関しては、次のように書かれています。

> 文字列が半角カナを含んでいる時、文字コードが EUC であるか シフトJIS であるかの判断は非常に困難で、時には誤った結果を返すことがあります。従って、半角カナは、文字コードの自動認識の判断対象からはずされます。文字列に半角カナを含むときの時の、文字コードの自動認識は、保証されません。

文字コードの判別に失敗しているのだと思います。判別の精度を上げるために、input タグの hidden 属性を利用してダミーの文字列を使ってみてはどうでしょうか? CGI 側では捨てるだけで済みます。

<input type="hidden" name="judge" value="ここに判別用の少し長めの全角文字">
    • good
    • 0

#2の補足にあった例から言えば、誤判定されてる可能性が高いです。


自動判定というは、他のコードにない文字のならびや、使われている文字の比率から予想するもので、文字数が少ないと精度が落ちます。(短くても精度が高いのは、ESC等を使うjisくらいです)

特に、Shift_JISの半角カナはEUC-JPの漢字用の文字と重なる部分が多く、Shift-JISの半角カナが数文字あるだけでは、EUC-JPと誤判定されても不思議はありません。
# 試しに、EUC-JPで書かれたテキストをShift_jisで無理矢理開いてみてください。(ブラウザで文字コードをShift_jisに変更するでもいいです)半角カナの羅列になるはずです。


だから、#2さんも
『「文字コードの判定」が正しくできていることは確実なのですか?』
とおっしゃっているのです。

$kcodeを表示するなりファイルに保存するなりして、確認はしたのですか?

この回答への補足

>$kcodeを表示するなりファイルに保存するなりして、確認はしたのですか?
半角のアを入力した場合、$kcode=  (値なし)
半角のアイを入力した場合、$kcode=euc
全角のアを入力した場合、$kcode=sjis
全角のアイを入力した場合、$kcode=sjis
です。


なお、
&jcode'convert(*v,"sjis",$kcode);
をコメントアウトし、さらに
 if($kcode eq 'sjis') {
  &jcode::h2z_sjis(\$v);
 }
 if($kcode eq 'euc') {
  &jcode::h2z_euc(\$v);
 }
 if($kcode eq 'jis') {
  &jcode::h2z_jis(\$v);
 }

 if($kcode eq 'euc') {
  &jcode::h2z_sjis(\$v);
 }
のみにすると、半角カタカナの文字化けは解消されました。(理由は理解できていません)
ただし、文字化けは解消されたのですが、
 ・半角カタカナ1文字の場合、半角のまま。
 ・半角カタカナ2文字以上の場合、全角に変換。
 ・半角カタカナ1文字以上と全角カタカナの混在の場合、半角、全角それぞれそのまま。
 ・半角カタカナ1文字以上と漢字(又はひらがな)の混在の場合、半角カタカナは半角カタカナのまま。
 ・半角カタカナ1文字とブランクと半角カタカナ2文字以上の場合、全て半角のまま。
 ・半角カタカナ2文字以上とブランクと半角カタカナ2文字以上の場合、全て全角に変換。
という結果になりました。
つまり半角カタカナ1文字が入った場合、及び、半角カタカナとそれ以外の文字が混在する場合に、
正しい結果(半角カタカナ→全角カタカナ変換)が得られません。
引き続き、調査しておりますが、何かお分かりになられましたら、ご教授ねがいます。
よろしくお願いします。

補足日時:2010/11/12 09:33
    • good
    • 0

#2 の 2行目を無視された....

この回答への補足

>無視された....
「無視」という表現は、きわめて心外。
以上

補足日時:2010/11/11 14:11
    • good
    • 0

> &jcode'convert(*v,"sjis",$kcode);



> # 半角カナを全角に変換
> if($kcode eq 'sjis') {
>  &jcode::h2z_sjis(\$v);
> }
> if($kcode eq 'euc') {
> &jcode::h2z_euc(\$v);
> }
> if($kcode eq 'jis') {
> &jcode::h2z_jis(\$v);
> }

Shift_JIS に変換してから元の $kcode で半角全角の変換をするのは間違っているのでは?

&jcode'convert(*v,"sjis",$kcode);
&jcode::h2z_sjis(\$v);
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

> # 半角カナを全角に変換
> if($kcode eq 'sjis') {
>  &jcode::h2z_sjis(\$v);
> }
> if($kcode eq 'euc') {
> &jcode::h2z_euc(\$v);
> }
> if($kcode eq 'jis') {
> &jcode::h2z_jis(\$v);
> }
の部分を、
&jcode::h2z_sjis(\$v);
だけにしたのですが、
結果は同じ(半角カタカナの場合、文字化け)でした。

ご指摘は、こういう意味では、なかったのでしょうか。

お礼日時:2010/11/11 13:47

「うまくいかない」とは, 具体的には何がどう「うまくいかない」のですか?


「文字コードの判定」が正しくできていることは確実なのですか?

この回答への補足

アイウエオ → 渦慨オ
アイウエオ → アイウエオ
あいうえお → あいうえお
ガギグゲゴ → 衿迎五閤剤
ガギグゲゴ → ガギグゲゴ
亜意宇江尾 → 亜意宇江尾

です。

補足日時:2010/11/11 12:46
    • good
    • 0

どううまくいかないのでしょうか?


どんな具合なのか詳細に提示しないとコメントできません。

この回答への補足

回答番号:No.2の1行目と4行目のカタカナは、半角です。

補足日時:2010/11/11 12:49
    • good
    • 0

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