• ベストアンサー

1バイト文字と2バイト文字の区別の仕方

C++についての質問です。 簡単な質問で大変申し訳ございません。 '\'や'&'などSQLインジェクションに 関係する文字コードについて 空白に変換する処理をいれていたところ、 カタカナの「ソ」(%83%5c)など も変換されてしまい、 文字化けしてしまうという現象が起きています。 '\'は、'%5c'のため、カタカナの「ソ」は、 それと同じ'5c'のコードが 2バイト目入ってしまっているからだと いう原因までは、 把握しているのですが、 対処の仕方がわかりません。 簡単な質問で申し訳ございませんが ご教示願います。

質問者が選んだベストアンサー

  • ベストアンサー
  • Willyt
  • ベストアンサー率25% (2858/11131)
回答No.3

 文字コードを空白に変換するというのは危ないのではないでしょうか。文字化けが起きたということはそのコードの中の1ビットが化けたか、データが混入したか、脱落したかが考えられます。それのどれであるかということは前後のデータの並び方から推定する他はないのですが、これはかなり大変な作業になります。  ですからデータを頭から正しいものと決め込んで特殊コードを空白コードに変換する作業を機械的に行なうということは大変危険な作業であるということになり、文字化けが起きたときには作業を中止し、その原因を推定するルーチンに飛込むようにしなければなりませんね。  今回の場合はデータがずれてしまっているようですから、これは1ビット脱落したか混入したかのどちからですから、場合に分けたルーチンを用意するのも一つの手段かと思います。  いずれにせよ、データをいじるのは大変危険な作業なので、薄氷を踏むような用心が必要ということになりますね。  私が現場でやっていた頃はまだすべて2バイトコードでしたが、それでも血の出るような思いを何度もしたことがあります。御苦労はお察ししますよ。

参考URL:
http://home.a03.itscom.net/tsuzu/programing/tips07.htm
googoocgi
質問者

お礼

お忙しい中、返信くださいまして どうもありがとうございます。 実際に行っている処理としては、 「サシスセソ」という文字列に 「\」、「'」、「"」、「&」などの不正コードが 入力されてしまった場合は、 // 文字列除去処理 int find_len = strlen(find); char *start = str; char *hit; while ( ( hit = strstr(start, find) ) ){ strcpy( hit, hit+find_len ); } 不正文字を詰めるようにしています。 ただし、上記処理をあらゆる文字に対し行った場合は、 文字が落ちてしまうため、 2バイト文字については、文字列除去処理を行いたくありません。 そこで、以下の処理を書いています。 #define 2bytechar(c) ((((unsigned char)(c))!=0x7F)&&(((unsigned char)(c))>=0x40)&&(((unsigned char)(c))<=0xFC)) for ( i=0; str[i] != '\0' i++ ) { if ( 2bytechar( str[i] ) ){ //進める  i++; } else { //文字列除去処理呼び出し } しかし、 上記の場合は、 「サシスセソ」が文字化けすることはなくなりましたが、 「\サシスセソ」とした場合は、 「\」が削除されなくなってしまいました。 どのように対応すればよいでしょうか? 拙い文章な上に、 細かい部分まで質問してしまいまして 申し訳ございませんが、 宜しくお願い申し上げます

その他の回答 (4)

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.5

> #define 2bytechar(c) ((((unsigned char)(c))!=0x7F)&&(((unsigned char)(c))>=0x40)&&(((unsigned char)(c))<=0xFC)) このマクロのロジック間違っていませんか? 後の処理とあわせて考えると多分ShiftJISの上位バイトとみなせる ときに下位バイトを処理対象からはずすということをしたいのでしょうけど、 上記のマクロでは 1. 0x7f ではなく 2. 0x40 <= x <= 0xFC の範囲にあるキャラクタのときに真になりますから、'\'をこのマクロに 食わせると真になってしまいます。 ShiftJISの上位バイトの分布をもう一度見直してみては? もしWindows上のC処理系を使っているのなら、判定を行ってくれる関数が多分ありますし、Windows APIにも存在しています。

  • Willyt
  • ベストアンサー率25% (2858/11131)
回答No.4

>「\サシスセソ」とした場合は、「\」が削除されなくなってしまいました。  ご呈示のロジックなら独り¥だけが残る筈がありませんよね。これはC++のスペックで \ に何か特殊の意味を与えていて、組み込み関数がこれを無視するからではないかと推測します。  ですからこれの対策は1バイトを切出したときに組み込み関数で2バイトコードと1バイトコードを弁別するのをやめて、ビットオペレーションを使い、自前で判断することでしか解決できないと思います。コード表をにらみながら効率的なルーチンを編み出してください。20年若ければご一緒に考えるところですが、古稀に近くなるともうダメです(^_^;)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

拡張文字集合の扱いは、今直面している0x5cの問題だけでなく、その他のこともすべて視野に入れた上で、どうすべきか決定する必要があると思います。 文字列中の文字をランダムアクセスする頻度が赤いのであればワイド文字列に直した方がよいでしょうし、文字列の順序付けを変更したくないのであれば、シフトJISのままにしておく必要があります。

  • galluda
  • ベストアンサー率35% (440/1242)
回答No.1

がると申します。 基本的にはshift-jisに起因する問題になります。 ですので、対応策としては ・文字コードをあらかじめshift-jis以外(通例EUC。最近だとUTF-8であることも多い)に変換する ・Shift-jisコードであるかどうかを1バイト目の値で判断する のいずれかになるかと思います。 とりあえずお勧めは1番目でしょうか? 結局のところ、こういう部分が「内部処理でsjis使うな」といわれている所以なので。

関連するQ&A