掲示板などで、半角・機種依存文字のチェックを行うには?

[上に] [前に] [次に]
柳生烈堂 2000/01/14(金) 14:13:56
 半角・機種依存文字を掲示板に書き込む人が多いので、懲らしめるために(オイオイ)チェック機能を入れてやろうかと思っています。

 $valueにデータが入ってるとして、その中に半角・機種依存文字が入っていたら、それを$damenamojiに出力してエラーメッセージを出そうと思うのですが

...........;
...........;
if (.........) {
  &error('「$damenamoji」は半角または機種依存文字です。別の文字に置き換えてください');
}

sub error {
  エラー出力処理;
}

$valueの判定、及び$damenamojiへの出力をどのようにすればいいでしょうか?

 どのようにしたら

B-Cus 2000/01/15(土) 07:43:26
文字コードは SJIS ですか? EUC ですか?
# SJIS なら mm さんにまかせた。

EUC なら
 http://X68000.startshop.co.jp/~68user/cgi-bin/view-script.cgi/wwwboard.cgi
の、
 sub conv_windows_char(\$)
 sub init_windows_char {
をコピーして、
  if ( conv_windows_char($line) ){
     print "$line";
     print "赤色の文字は機種依存文字です";
  }
てな感じです。

なお、これはまだ半角カナには対応してません。

B-Cus 2000/01/15(土) 08:33:03
あ〜、置換しちゃいかんよね。どの文字がまずいのか
利用者に教えるのが目的だからね。適当に改造してみて、
もしわからんかったら また聞いて下さい。

なお、EUC の半角カナ自体は \x8E[\xA0-\x8E] で検索できるので、
追加するのは難しくはないです。
# SJIS なら \xA0-\x8E だけど、mm さんにまかせた :-)

andi 2000/01/15(土) 12:44:16
横から申し訳ありません。
どこかに文字コードの一覧表ってありませんでしょうか。
平仮名の文字コードが知りたいのですが・・・

mm 2000/01/15(土) 13:06:20
># SJIS なら mm さんにまかせた。
ありゃ、昨日見たときは、B-Cusさんが回答するだろうなぁ…と思ってたら(^^;

出掛ける前なので、ちゃんと読んでませんが、一応参考資料です↓
http://www2s.biglobe.ne.jp/~cru/library/junk/winsjis.pl
http://www2s.biglobe.ne.jp/~cru/library/junk/winsjis4.pl

柳生烈堂 2000/01/17(月) 14:56:04
漢字コードはSJISです。

require './kishu.pl';

&kishu'check($FORM{'value'},$damenamoji); ##############
if ($damenamoji) { &error('145',"$damenamojiは半角または機種依存文字です。別の文字に置き換えてください。"); }

package kishu;
@kishuizon = (
'@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S',
'_','`','a','b','c','d','e','g','h','i','j','k','l','m','n','o','p','q','r','s',
't','u','~','','','','','','','','','','','','','','','','≒','≡',
'∫','','','√','⊥','∠','','','∵','∩','∪',
'。','「','」','、','・','ヲ','ァ','ィ','ゥ','ェ','ォ','ャ','ュ','ョ','ッ','ー','ア','イ','ウ','エ','オ','カ','キ','ク','ケ','コ','サ','シ','ス','セ','ソ','タ','チ','ツ','テ','ト','ナ','ニ','ヌ','メ','ノ','ハ','ヒ','フ','ヘ','ホ','マ','ミ','ム','メ','モ','ヤ','ユ','ヨ','ラ','リ','ル','レ','ロ','ワ','ン',
);
##### &kishu'check(元データ,ダメな文字); ##########################################
sub check {
   foreach $damenamoji(@kishuizon) {
      if ($_[0] =~ /$damenamoji/) {
         $_[1] .= $damenamoji;
      }
   }
}
#
1;

 とりあえず、こんなかんじで作ってみましたが、うまく行きません。
 「テあいうキえお@Aあいアうえお」という文字列で試験したのですが(Windowsマシンから)、エラーメッセージは「@A「、ヲィアキテは半角または機種依存…」となってしまいました(「、ヲィのチェックを余分にしてしまう?)。

 あと、@kishuizonの中に(Windowsの)ギリシャ数字を入れると、なぜかperlが落ちてしまいます(kishuの中で)。

 以上2点はどうしてなんでしょうか?


 あと、もう一点。
 この処理は、それがしも思ったのですが、やたらループが多すぎて時間を食うんじゃないかと思います。
 文字コード判定で、もっと楽な方法があれば御教授願います。

きたむら 2000/01/18(火) 07:30:51
>「、ヲィのチェックを余分にしてしまう?)。

これらの半角カナの文字コードは 0xA2、0xA4、0xA6、0xA8なので、"い"、"う"、"え","お"(0x82A2、0x82A4、0x82A6、0x82A8)とぶつかってしまいます。半角カナ検査と機種依存文字検査は別々にしたほうがいいかもしれません。

ためしに作ってみました。シフトJIS専用です。前半が半角カナ、後半が機種依存文字のチェックです。(やや動作に自信なし)

$kishuizon =
'@|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|' .
'_|`|a|b|c|d|e|g|h|i|j|k|l|m|n|o|p|q|r|s|' .
't|u|~||−|ポл||||榎掛弓芸鋼楯≒|≡|' .
'∫|倒培√|⊥|∠||處∵|∩|∪';

sub check {
$_[0] =~ s/(^|[^\x81-\x9f\xe0-\xfc])([\xa1-\xdf])/$_[1].=$2,$1.$2/ge;
$_[0] =~ s/($kishuizon)/$_[1].=$1,$1/ge;
}

ギリシャ数字で落ちる理由はわかりませんでした。ていうか、ギリシャ数字って文字コードのどこらへんでしたっけ?

柳生烈堂 2000/01/18(火) 09:18:40
[[解決]]
きたむらさん作成のものでうまくいきました。
丸付き数字も、$kishuizonの中に入れて大丈夫でした。
ありがとうございました。

B-Cus 2000/01/19(水) 21:40:15
元質問者は紹介したリンクを見る気が全くないようですね。

後に誰かがこのコードを参考にするといけないので、某所での
mm さんの指摘を引用します。
---------------------------------
>$_[0] =~ s/(^|[^\x81-\x9f\xe0-\xfc])([\xa1-\xdf])/$_[1].=$2,$1.$2/ge;
・[\x81-\x9f\xe0-\xfc]が第2バイトになる日本語の直後の半角カナは取りこぼす。
・半角カナが連続する場合、1個置きにしかマッチしない。

>$_[0] =~ s/($kishuizon)/$_[1].=$1,$1/ge;
・第2・第1バイトの文字間にミスマッチする。
・ローマ数字などのように第2バイトに正規表現のメタキャラクタがある文字を追加し難い。

従って、
 $FORM{'value'} = "gifファイル"; # `ファイル'は半角カナ
の場合、「gi」の文字間で「No.」がミスマッチし、「フ」と「イ」が検出できません。
----------------------------------

きたむら 2000/01/20(木) 04:06:20
うう。申し訳ありません。
動作確認してないコードを公開したことを猛省中。
C-Busさん、mmさん、ありがとう。

柳生烈堂 2000/01/20(木) 08:46:13
> 元質問者は紹介したリンクを見る気が全くないようですね。

いやぁ、見ましたよ。B-Cus殿のも、MM殿のも。

ただ、既存のスクリプトから呼ぶのにどうやったらいいのかが不明で、さらにはエラーを返すために改造せねばならなかったので、だったら使い方がすぐに分かったきたむらさんのを選んだというわけで…。

mm 2000/01/20(木) 21:18:17
きたむらさん、柳生烈堂さん
指摘しても嫌味にしかならないだろうと思って、こちらには書かなかったのですが、
まだまだ私の人を見る目が未熟なようです。失礼致しましたm(_ _)m

先のURLのものは少し勘違いやバグがあったので、
機種依存文字を第1バイト単位(2区単位)でしか指定できないんですが、
柳生烈堂さんの仕様も含めて書き換えてみました。(perl5依存です)

B-Cus さん
13区と89-92区と115-119区を機種依存文字に決め付けてますが
問題ないですよね…?
それと、$FORM{'value'} が引数で渡せないので、プロトタイプ宣言は止めました。

柳生烈堂さん
require 'depwin.pl';
$damenamoji = depwin::get_windows_char( \$FORM{'value'} );
if ( $damenamoji ne '' ) {
&error('145',"'$damenamoji' は半角カナまたは機種依存文字です。別の文字に置き換えてください。");
}
という感じで使えると思います。
ただし、get_windows_char しか使わないのなら、%conv_table の作成は冗長です。

http://www2s.biglobe.ne.jp/~cru/library/junk/depwin.pl
--------------------------- depwin.pl ------------------------------------
package depwin;
# Shift-JIS用 Windows 機種依存文字の検査/変換ルーチン(perl5)
# 検査/変換対象は、半角カナと13区,89-92区,115-119区
# B-Cus さんの http://X68000.startshop.co.jp/~68user/cgi-bin/view-script.cgi/wwwboard.cgi を Shift-JIS 用に書き換えてもらったものを半角カナ対応
# Windows 機種依存文字は、http://www2d.biglobe.ne.jp/~msyk/charcode/kisyuizon/msgotic.html を参考にしました。
# /\G((?:$ascii|$sjis_twoBytes)*?)($sjis_pattern)/ のパターンマッチは、大崎博基さん(http://www.din.or.jp/~ohzaki/)のアドバイスを受けました。
#---------------------------------------------------------------
# Windows 機種依存文字を変換。引数を直接書き換えるので注意。
# 見付かれば正数を、見付からなかったら0を返す。
sub conv_windows_char {
my ($str)=@_;
&init_windows_char unless defined %conv_table; # 1回目のみテーブルを初期化
$$str =~ s/\G((?:$ascii|$sjis_twoBytes)*?)($sjis_pattern)/$1.($conv_table{$2}||'〓')/oeg;
# 下3行は、赤色に変える場合(上の1行と入れ替え)
# my $found_flg = 0;
# $found_flg = $$str =~ s%\G((?:$ascii|$sjis_twoBytes)*?)($sjis_pattern)%"$1<FONT COLOR=red>".($conv_table{$2}||'〓')."</FONT>"%oeg;
# $found_flg;
}
#---------------------------------------------------------------
# Windows 機種依存文字を検査する。引数は書き換えない。
# 見付けた機種依存文字の文字列を返す。見付からなければ '' を返す。
sub get_windows_char {
my ($str)=@_;
&init_windows_char unless defined %conv_table; # 1回目のみテーブルを初期化
join '', $$str =~ m/\G(?:$ascii|$sjis_twoBytes)*?((?:$sjis_pattern)+)/og;
}
#---------------------------------------------------------------
# Windows 機種依存文字の変換テーブルを初期化
sub init_windows_char {
%conv_data = (
0xA0=> # 半角カナ
'  。 「 」 、 ・ ヲ ァ ィ ゥ ェ ォ ャ ュ ョ ッ ー
ア イ ウ エ オ カ キ ク ケ コ サ シ ス セ ソ タ チ ツ テ ト
ナ ニ ヌ メ ノ ハ ヒ フ ヘ ホ マ ミ ム メ モ ヤ ユ ヨ ラ リ
ル レ ロ ワ ン ゛ ゜',

0x8740=> # 13区
'(1) (2) (3) (4) (5) (6) (7) (8) (9)
(10) (11) (12) (13) (14) (15) (16)
(17) (18) (19) (20) I II III IV
V VI VII VIII IX X . ミリ
キロ センチ メートル グラム トン アール ヘクタール リットル
ワット カロリー ドル セント パーセント ミリバール ページ mm
cm km mg kg cc m^2 〓 〓 〓 〓 〓 〓 〓 〓 平成',

0x8780=> # 13区
'" ,, No. K.K. Tel (上) (中) (下) (左)
(右) (株) (有) (代) 明治 大正 昭和
≒ ≡ ∫ ∫ Σ √ ⊥
∠ L △ ∵ ∩ ∪',

0xEEEF=> # 92区
q{i ii iii iv v vi vii viii ix x ¬ | ' ''},

0xFA40=> # 115区
q{i ii iii iv v vi vii viii ix x
I II III IV V VI VII VIII IX X ¬ | ' ''
(株) No. Tel ∵ },
);
foreach (keys %conv_data){
$base_code = $_;
@chars = split(/\s+/,$conv_data{$_});
foreach (@chars){ # ↓ tr/\0//d は1バイトの半角カナ用
($char_code = pack('C*',$base_code/256,$base_code%256)) =~ tr/\0//d;
$conv_table{$char_code} = $_;
$base_code++;
}
}
$ascii = '[\x00-\x7F]';
$sjis_twoBytes = '[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC]';
# ↓半角カナと13区(\x87),89-92区(\xED\xEE),115-119区(\xFA-\xFC)
$sjis_pattern='[\xA0-\xDF]|[\x87\xED\xEE\xFA-\xFC][\x40-\x7E\x80-\xFC]';
}
1;

柳生烈堂 2000/01/21(金) 09:26:57
mm殿、ご親切に作りなおしていただいて、かたじけのうございます。

半角・機種依存文字を警告する場合には、
require 'depwin.pl';
$damenamoji = depwin::get_windows_char( \$FORM{'value'} );
if ( $damenamoji ne '' ) {
&error('145',"'$damenamoji' は半角カナまたは機種依存文字です。別の文字に置き換えてください。");
}

変換する場合には
require 'depwin.pl';
depwin::conv_windows_char( \$FORM{'value'} );

で今のところ、正常に動いております。
ただ、

> ただし、get_windows_char しか使わないのなら、%conv_table の作成は冗長です。

とのことだったので、
sub conv_windows_char の後ろに

$conv = 1;

を追加し、sub init_windows_char内を以下のように変更してみました。

if ($conv) { ################# ←追加
   foreach (keys %conv_data){
      $base_code = $_;
      @chars = split(/\s+/,$conv_data{$_});
      foreach (@chars){  # ↓ tr/\0//d は1バイトの半角カナ用
        ($char_code = pack('C*',$base_code/256,$base_code%256)) =~ tr/\0//d;
        $conv_table{$char_code} = $_;
        $base_code++;
      }
   }
} #################### ←追加

とりあえず、これで動いてますが、なにか処理の修正がおかしければ御指摘をお願い致し申しあげます。

mm 2000/01/21(金) 22:45:13
>なにか処理の修正がおかしければ御指摘をお願い致し申しあげます。
sub get_windows_char のみを使うのであれば、単に↓でいいです。
ただし、検出文字を個々に指定したい場合には、先の %conv_table を利用して、
正規表現あたりをちょっと書き換えれば対応可能なので、適当に改造して下さい。

package depwin;
sub get_windows_char {
my ($str)=@_;
join '', $$str =~ m/\G(?:$ascii|$sjis_twoBytes)*?((?:$sjis_pattern)+)/og;
}
$ascii = '[\x00-\x7F]';
$sjis_twoBytes = '[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC]';
$sjis_pattern='[\xA0-\xDF]|[\x87\xED\xEE\xFA-\xFC][\x40-\x7E\x80-\xFC]';

[上に] [前に] [次に]