こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

全角数字、アルファベット大小を認識させたいのですが上手くいきません

入力文字列が、全角数字なのか、全角アルファベットなのか、或いはそれ以外なのかを判断させたいのですが、

以下の「testfunc」では、全角数字、全角アルファベットの大文字のみ判断可能で、全角アルファベットの小文字が、全角英数以外と認識されてしまいます。

どうすれば、全角アルファベットの小文字も認識できるようになるでしょうか?

どなたかよいアドバイスをください。

#include <stdio.h>

int testfunc (char *c) {

unsigned a, b;
a = c[0];//上位バイト
b = c[1];//下位バイト

if ((a >= 0x82) && ((b >= 0x4f) && (b <= 0x58))){//全角0~9
return 2;
} else if ((a >= 0x82) && ((b >= 0x60) && (b <= 0x9a))){//全角A~z
return 1;
} else {
return 0;
}
}

投稿日時 - 2009-06-28 18:41:58

QNo.5081904

困ってます

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

ロケールとかの問題じゃない。根本から間違ってる。

a = c[0];
って書いてあると、まず、c[0]はintに拡張され、それからunsignedに変換され、aに代入される。

もしc[0]に「a」の第1バイトが入っているなら、c[0]は「charで-126」になる。16進数では「0x82」になる。

そして、それがintに拡張され「intで-126」になる。intが32ビットなら、16進数では「0xFFFFFF82」になる。これは「0x00000082」ではない。

そして次に、それがunsignedに変換される。16進数で「0xFFFFFF82」なので10進数では「4294967170」になる。これも当然「0x00000082」ではない。

最終的にaに代入されるのは「4294967170」であって、質問者さんが期待する「0x82」が代入される事は永久にない。

bについても同様の事が起きる。

結果、c[0]、c[1]の値とa、bの値は、以下のようになる。
c[0]の値      aの値
0x00~0x7F ⇒ 0x00000000~0x0000007F
0x80~0xFF ⇒ 0xFFFFFF80~0xFFFFFFFF
c[1]の値      bの値
0x00~0x7F ⇒ 0x00000000~0x0000007F
0x80~0xFF ⇒ 0xFFFFFF80~0xFFFFFFFF

さて、全角の「0」~「9」が来た時、aとbはどうなるだろう。

c[0]は0x82、c[1]は0x4F~0x58なので

c[0]の値      aの値
0x80~0xFF ⇒ 0xFFFFFF80~0xFFFFFFFF
c[1]の値      bの値
0x00~0x7F ⇒ 0x00000000~0x0000007F

の変換が行われ

aの値=0xFFFFFF82(4294967170)
bの値=0x0000004F~0x00000058

となる。

これは

if ((a >= 0x82) && ((b >= 0x4f) && (b <= 0x58))){//全角0~9

の条件を満たすので

return 2;

を実行する。

たぶん、最初、質問者さんは

if ((a == 0x82) && ((b >= 0x4f) && (b <= 0x58))){//全角0~9

と書いて、return 2が実行されないから

if ((a >= 0x82) && ((b >= 0x4f) && (b <= 0x58))){//全角0~9

って書いたんだと思う。でも、それは「大きな間違い」で、本当は

if ((a == 0xffffff82) && ((b >= 0x4f) && (b <= 0x58))){//全角0~9

って書かなきゃいけなかった。

今のまま

if ((a >= 0x82) && ((b >= 0x4f) && (b <= 0x58))){//全角0~9

って書いてると、全角0~9以外の文字であっても、第1バイトが0x82~0xffで、第2バイトが0x4f~0x58の範囲なら、全部「全角0~9」と判断される筈。例えば「グケゲコゴサザシジス」とか「ОПРСТУФХЦЧ」とかも「全角0~9」って判断する。

さて、次。全角の「A」~「Z」が来た時、aとbはどうなるだろう。

c[0]は0x82、c[1]は0x60~0x7aなので

c[0]の値      aの値
0x80~0xFF ⇒ 0xFFFFFF80~0xFFFFFFFF
c[1]の値      bの値
0x00~0x7F ⇒ 0x00000000~0x0000007F

の変換が行われ

aの値=0xFFFFFF82(4294967170)
bの値=0x00000060~0x0000007A

となる。

これは

if ((a >= 0x82) && ((b >= 0x4f) && (b <= 0x58))){//全角0~9

の条件は満たさないが

if ((a >= 0x82) && ((b >= 0x60) && (b <= 0x9a))){//全角A~z

の条件を満たすので

return 1;

を実行する。

さて、問題の「a」~「z」が来た時、aとbはどうなるだろう。

c[0]は0x82、c[1]は0x81~0x9bなので

c[0]の値      aの値
0x80~0xFF ⇒ 0xFFFFFF80~0xFFFFFFFF
c[1]の値      bの値
0x80~0xFF ⇒ 0xFFFFFF80~0xFFFFFFFF

の変換が行われ

aの値=0xFFFFFF82(4294967170)
bの値=0xFFFFFF81~0x0000009B(4294967169~4294967195)

となる。

これは

if ((a >= 0x82) && ((b >= 0x4f) && (b <= 0x58))){//全角0~9

の条件も

if ((a >= 0x82) && ((b >= 0x60) && (b <= 0x9a))){//全角A~z

の条件も、どちらも満たさないので、

return 0;

を実行する。

はい、もう何が悪いか判りましたね?

質問者さんが「charの値を、何もしないでunsignedに放り込んだのが悪い」のです。

最低限、以下の3つは覚えておこう。

「charの最上位ビットが1の値、つまり、0x80~0xFFは負数である」

「charを計算式に書くと、一旦、intにされ、負数は符号拡張される」

「charの0x82と、intの0x82(というか、0x00000082)は等しくない」

関数を以下のように直せば、動く筈。

int testfunc (char *c) {

unsigned a, b;
a = (unsigned)(c[0]) & 0x000000FFU;//上位バイト
b = (unsigned)(c[1]) & 0x000000FFU;//下位バイト

/******ちゃんと動かないからって無理やり動くようにした「(a >= 0x82」は愚かな修正なので「a == 0x82」に戻しておくこと!!!******/
if ((a == 0x82) && ((b >= 0x4f) && (b <= 0x58))){//全角0~9
return 2;
/******ちゃんと動かないからって無理やり動くようにした「(a >= 0x82」は愚かな修正なので「a == 0x82」に戻しておくこと!!!******/
} else if ((a == 0x82) && ((b >= 0x60) && (b <= 0x9a))){//全角A~z
return 1;
} else {
return 0;
}
}

キャストと型変換の基本が理解出来てないので、2年くらい修行し直すこと。

ロケールがどうとかって、根本原因を読み取れない回答者さんが多過ぎ。書いてあるコード見れば「S-JISを想定している」くらいの事は読み取れるだろ。ロケールをどうこう言う前にさ。
(現代の若者って、こういう「相手が何を言いたいか」を読み取る能力が完璧に欠如してると思うが、どうだろう?)

こういう回答をする回答者さん達って、質問者さんと同様、基本が出来てないんだろうな。

投稿日時 - 2009-06-29 12:40:45

お礼

>「charの0x82と、intの0x82(というか、0x00000082)は等しくない」
なるほど大きな誤解をしていました。

>キャストと型変換の基本が理解出来てないので、2年くらい修行し直すこと。
そうですね。2年くらい修行し直します。

ありがとうございました。

投稿日時 - 2009-06-29 23:31:29

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(3)

ANo.3

char型が符号付きか符号無しかが処理系定義であることは、C言語をまともに勉強したものであれば知っていて当然のことです。OSが何であるかは関係なく、コンパイラとコンパイルオプションに依存します。

また、char型がint型と同じサイズである可能性も(どんなに確率が低くても)処理系が特定されない限り否定しきれません。
# どこかの会社の内製コンパイラかもしれませんし、シミュレーション環境やその他のインタープリタの可能性も否定しきれませんので。

さらに、一見シフトJISのように見えても、Big5のような類似のコードを使っている文字コードや特定の会社の内製文字コードの可能性も否定しきれませんし、TRONコードのようなものかもしれません。これらを決めうちにしているのか、ロケールに依存させるつもりなのかも、この関数を見ただけでは判断不能です。

勝手に決めつけるのは簡単ですが、正確な回答は正確な質問からしか(偶然を除いて)出てきません。

投稿日時 - 2009-06-29 19:05:46

ANo.1

環境やロケールに依存しない方法はありません。
環境およびロケールを明確にしてください。

投稿日時 - 2009-06-28 18:47:45

補足

情報が足りなかったようで申し訳ありません。
Windows XPで、ShiftJisの文字を認識させようとしています。

投稿日時 - 2009-06-28 21:33:26

あなたにオススメの質問