• ベストアンサー

全角文字のチェック

現在C言語を勉強しております。 そこで、キーボードから入力された文字列のチェックを行う関数を作成したいのですが、実装方法が分かりません・・・。 以下に仕様と私の作成したソースを貼ります。 【許可する文字】は、 全角のひらがな 全角の英語(大文字も小文字もOK) 全角の数字 です。 チェックする関数を作成したいのですが、以下ではうまくいかず・・・ 教えてくださいorz 比較の仕方がおかしいのかな・・・とは思っているんですが。 関数は、引数として渡された文字列に許可以外の文字が含まれている場合は1を、そうでなければ0を返す、という仕様にしたいです。 int checkName(char *str) { int i; for(i = 0; str[i] != '\n'; i++){ /* 奇数バイトをチェック */ if(str[i] != 0x82){ return 1; }else{ i++; /* ひらがな以外の場合 */ if(str[i] < 0xa0 && str[i] > 0xf1) /* 英語(大文字)以外の場合 */ if(str[i] < 0x60 && str[i] > 0x79) /* 英語(小文字)以外の場合 */ if(str[i] < 0x81 && str[i] > 0x9a) /* 数字の場合 */ if(str[i] < 0x50 && str[i] > 0x58) /* 許可する文字に該当しなかった場合は1を返す */ return 1; } } return 0; } 上記ソースの「(str[i] != 0x82)」は比較の仕方としておかしいでしょうか? 以上、よろしくお願いいたします。

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

  • ベストアンサー
回答No.5

読み直してみたら、かなり意味不明な文章だったかも。 No4と合わせて、長々とした文章で申し訳ありません。 コメント頂ける場合は、No4かNo5のどちらか、より参考になった方にだけ書いて下されば結構ですので。 No4を要約すると0x82がunsigned intだったと仮定した時、解決方法は3通りあるという事です。 1:if(str[i] != 0xffffff82)  とても強引な解決策です。これ10進で表すと-126ではなく、4294967170と比較するという意味になります。  そしてchar型の0x82をunsigned intすると、4294967170になると言う事でもあります。  (C言語の規格に疎いので断定は出来ないのですけど、ya-chaさんの環境でも同じ値になると思われます) 2:if((unsigned char)str[i] != 0x82)  ya-chaさんの解法です。  3通りの中で一番スマートな解法です。  仮にstr[i]をunsigned intにキャストしても、0x00000082→0x82ですから、結果として希望通りの動作になります。  文字コードにマイナスは必要ないわけですから、unsignedにするのが無難というか、常識な様な気がしますね。  (私もそこら辺を意識した事はないのですけど) 3:if(str[i]) != (char)0x82)  これでも正常に動作します。この場合0x82は-126です。  解法2の場合、変数をunsigned charで宣言すればキャストの必要はありません。  しかし、この解法はchar型の変数と比較する事を前提にしてますので、(char)0x82は必須です。  ですので、可読性だけでなく処理速度面でみても解法2に劣ります。

ya-cha
質問者

お礼

何度も丁寧にご解説いただきありがとうございます。 お礼も遅くなりまして申し訳ございません。 引数をunsigned charにすることで解決出来、動作も確認済みです。 本当にありがとうございました。

その他の回答 (4)

回答No.4

言葉が足りない上に余計なお節介までしてしまいました。 もう本当すいません、いろいろと。 >ちなみに私の環境だと、str[0]はffffff82と表示されました。 後述とはこれの事です。 それと今気づいたんですけど、 >if(str[i] != 0x82) この0x82って、少なくとも符号なしですよね。 と言う事は、10進で表すとこうなります。(str[i]=0x82) if(-126 != 130){} そして私の環境の場合0x82はunsigned intと予想され、str[i]は暗黙的にunsigned intにキャストされます。 つまり、str[i]はこう変換されるはずです。 0x82 → 0xffffff82(-126なのでfで埋める) というわけで、どちらにしろ思い通りに動作しないという事になりそうですね。 逆に考えると、こうやっても良いはずです。 if(str[i] != (char)0x82){} ←0x82じゃなくてstr[i]の方に合わせなさい

回答No.3

if(str[i] != 0xffffff82)と書く事で、マッチする可能性があります。 理由は後述します。 そこまで原因が絞れていれば、printfを書けば確認出来ますよ。 for(i = 0; str[i] != '\n'; i++){ printf("%x\n",str[i]);   ←ここにprintfを挟む /* 奇数バイトをチェック */ if(str[i] != 0x82){ ちなみに私の環境だと、str[0]はffffff82と表示されました。 if(str[0] == 0x82)と試しみると、やっぱりマッチしません。 if(str[0] == 0xffffff82)でマッチしました。 ところで話は変わりますが。 Cで文字列を扱うのは、かなり現実的ではないと思います。 一度C#かjavaを経験されてみると、Cがどれだけ面倒くさくて分かりづらい事か分かると思います。 極力Cで記述したいのでしたら、私の場合は文字列の処理のみC++で組みますね。

参考URL:
http://programmer-toy-box.sblo.jp/article/16381630.html
ya-cha
質問者

お礼

ご回答ありがとうございます。 charをunsignedに変更して比較することで解決出来ました。 (よく理由はわかってないですが・・・orz) javaは経験あります。 C言語がとても面倒なのはすごく分かっておりますが、勉強なので・・・。 丁寧にソースを含めての説明本当にありがとうございました。 もし可能でしたら、 >理由は後述します。 の理由を教えていただけないでしょうか? しばらく質問は締め切らずに置いておくので・・・

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

多バイト文字かどうかの判定ならともかく、全角か半角かの判定は処理系や文字コードを特定しない限り無理です。 必要な情報を提供してください。

ya-cha
質問者

お礼

ご回答ありがとうございます。 charをunsignedに変更して比較することで解決出来ました。

noname#131718
noname#131718
回答No.1

比較はあってるんじゃないですかね? やってみていないので、そちらでprintfしてみて出れば正しいと思います。 しかしelseの中のif文が何かおかしい気がします。 ifで条件分岐しているのにもかかわらずその後の処理が書かれていないのでは? たしか{}でくくられていなければ次の一文が実行されるはずですが、その知識が正しければ次々と条件に一致するとそれぞれの下のif文を繰り返して、全ての条件をクリアすればreturn 1になるはずです。(違ったらすいません) ですがstr[i]の値的に同時に全ての条件を満たすことはないと思われます。 簡単な方法はそれぞれのif文の後にreturn 1;を書いてあげることですかね。 プログラムとしてどうかと思いますが・・・ 回答にならなくてすいません。

ya-cha
質問者

お礼

デバッグしてみたら、「(str[i] != 0x82)」が一致しないんです・・・。 if文についての指摘は回答者様の言われるとおりですね・・・orz まだまだ初心者なもので失礼いたしました。

関連するQ&A