全角数字、アルファベット大小を認識する方法とは?

このQ&Aのポイント
  • 入力文字列が、全角数字なのか、全角アルファベットなのか、或いはそれ以外なのかを判断する方法がわかりません。
  • 現在の「testfunc」では、全角数字と全角アルファベットの大文字のみを判断することができますが、全角アルファベットの小文字を判断することができません。
  • 全角アルファベットの小文字も認識するための方法を教えてください。
回答を見る
  • ベストアンサー

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

入力文字列が、全角数字なのか、全角アルファベットなのか、或いはそれ以外なのかを判断させたいのですが、 以下の「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; } }

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

  • ベストアンサー
  • chie65535
  • ベストアンサー率43% (8519/19367)
回答No.2

ロケールとかの問題じゃない。根本から間違ってる。 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を想定している」くらいの事は読み取れるだろ。ロケールをどうこう言う前にさ。 (現代の若者って、こういう「相手が何を言いたいか」を読み取る能力が完璧に欠如してると思うが、どうだろう?) こういう回答をする回答者さん達って、質問者さんと同様、基本が出来てないんだろうな。

trjun09
質問者

お礼

>「charの0x82と、intの0x82(というか、0x00000082)は等しくない」 なるほど大きな誤解をしていました。 >キャストと型変換の基本が理解出来てないので、2年くらい修行し直すこと。 そうですね。2年くらい修行し直します。 ありがとうございました。

その他の回答 (2)

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

char型が符号付きか符号無しかが処理系定義であることは、C言語をまともに勉強したものであれば知っていて当然のことです。OSが何であるかは関係なく、コンパイラとコンパイルオプションに依存します。 また、char型がint型と同じサイズである可能性も(どんなに確率が低くても)処理系が特定されない限り否定しきれません。 # どこかの会社の内製コンパイラかもしれませんし、シミュレーション環境やその他のインタープリタの可能性も否定しきれませんので。 さらに、一見シフトJISのように見えても、Big5のような類似のコードを使っている文字コードや特定の会社の内製文字コードの可能性も否定しきれませんし、TRONコードのようなものかもしれません。これらを決めうちにしているのか、ロケールに依存させるつもりなのかも、この関数を見ただけでは判断不能です。 勝手に決めつけるのは簡単ですが、正確な回答は正確な質問からしか(偶然を除いて)出てきません。

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

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

trjun09
質問者

補足

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

関連するQ&A

  • アルファベットと数字が入ったセルをただの数字として認識してほしいんです

    アルファベットと数字が入ったセルをただの数字として認識してほしいんです。 A1、B1セルに数値があり、 ・C1セルに「k10」と入力された時、D1セルに「10*B1」の計算結果を ・C1セルに「c/s100」と入力された時、D1セルに「100*A1」の計算結果を 自動表示されるようにしたいのですが・・関数などで何か方法はありますか? ※C1セルには「k○○」「c/s○○」の2種類あり、アルファベットと数字の間にセル内改行が入っています(○○は数字) ご存知の方、どうぞよろしくお願いします。 詳しくご回答いただけるととても助かります。

  • 全角文字のチェック

    現在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)」は比較の仕方としておかしいでしょうか? 以上、よろしくお願いいたします。

  • 全角文字の判定

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

  • 全角アルファベット(または数字)1文字による検索結果

    全角アルファベット(または数字)1文字を含んでいるものを問い合わせるときには、以下のようにLIKE句で指定しますが、 WHERE KOUJI_MEISYO LIKE '%A%' 検索結果には上記の例の場合、全角アルファベット「A」を含んでいるものがヒットしますが、中には全く含まれていないようなものがヒットする場合がありました。今回実際にあったものを載せておきますが、 (指名競争)大分都市計画道路県庁前古国府線道路測量設計業務委託 という文字列です。文字コードの並びで「A」と認識してしまうような症状に陥っているのかなと思いますが、このようなケースに遭われた方はいますか?きちんと検索できるようにするにはどうすればよろしいでしょうか? アドバイスやヒントを頂ければ幸いです。

  • CString型 全角半角を意識せずに「1文字」ずつ取り出す

    CString型の文字列に格納されている文字を1文字ずつ取り出したいです。 ただし半角なら1バイト単位で、全角なら2バイト単位で、という風に分離したいです。 半角だけなら、str[0] str[1]...という風に取り出せますが、 全角が混じっていると、1バイト目、2バイト目と分離されてしまいます。 その文字が半角か全角かを判断して、半角なら1バイト、全角なら2バイト同時に取り出すロジックを、下記のような感じの関数として作りたいです。 CString ripString(CString str,int index){ //ソースとなる文字列、n文字目 /*~処理~*/ return 文字列; } たとえば"あaいbうcえdおe"という文字列を入れると、 CString str="あaいbうcえdおe"; ripString(str,0) →結果 "あ" ripString(str,1) →結果 "a" ripString(str,2) →結果 "い" ripString(str,3) →結果 "b"  ・  ・  ・   こういうことをするのに良い方法はありますか? 1バイトごとのそれぞれの文字自身が、 ・半角文字なのか ・全角文字の前1バイトなのか ・全角文字の後1バイトなのか これをプログラム的に判別する方法があればいいのですが・・・悩んでいます。

  • 3つの入力した数値の大小比較ができません。

    #include<stdio.h> int main() { int a,b,c; scanf("%d",&a); scanf("%d",&b); scanf("%d",&c); if(a<b) { if(b<c) { if(a<c) { printf("%d<%d<%d\n",a,b,c); } else { printf("%d%d%d",a,b,c); } } if(b>c) { if(a>c) { printf("%d<%d<%d\n",c,b,a); } else { printf("%d<%d<%d\n",a,c,b); } } } else if(a>b) { if(b>c) { if(a>c) { printf("%d>%d>%d\n",a,b,c); } else { printf("%d>%d>%d\n",a,c,b); } } else if(b>c) { if(a>b) { printf("%d>%d>%d\n",a,b,c); } else { printf("%d>%d>%d\n",b,a,c); } } else if(c>b) { if(c>a) { printf("%d<%d<%d\n",b,a,c); } else { printf("%d>%d>%d\n",a,c,b); } } else if(a<c) { if(a<b) { printf("%d<%d<%d\n",a,b,c); } else { printf("%d<%d<%d\n",b,a,c); } } else if(a>c) { if(a<b) { printf("%d>%d>%d\n",b,a,c); } else { printf("%d>%d>%d\n",a,b,c); } } else { printf("%d=%d=%d\n",a,b,c); } } 間違っている部分を教えてください。

  • 打ち込んだ数字が素数かどうか判断するプログラム

    数字をキーボードから入力し、その数字が素数がどうかを判断するプログラムを打ちたいのですが、うまくできません。 コンパイルはできるのですが…。 どなたか間違っているところを教えてください。 #include<stdio.h> int main ( void ) { int a,b,indicator=1; printf("正の整数:"); scanf("%d", &a ); /* indicator=1.......素数でない indicator=0.......素数である */ if(a<=1){ indicator=1; } else { for(b=2;b<=(a-1);b++) { if(a%b == 0){ indicator=0; } } if(indicator==1) { printf("%dは素数ではありません\n",a); } else if (indicator==0) { printf("%dは素数です\n",a); } } return 0; }

  • アルファベット、数字を読み込んで変換出力

    アルファベット、数字を読み込んで、対応した文字、数字に変換し 出力したいのですが‥ 例えば [a-z ]= [1-26]と対応させ a,b,5,7 を読み込んで 1,2,e,g と出力させる感じです。 tr///などでコンパクトにまとめられるでしょうか? お教え願います。

    • ベストアンサー
    • Perl
  • Excel同一セル内の、アルファベットと数字を別々のセルに置き換える方法を教えてください

    ExcelのA列のセルに、アルファベットと数字の組み合わせが3000行くらい入っています。 アルファベットは1~5個でA~Z、 数字は1~3個で0~9  全て半角です。 の組み合わせです。アルファベットと数字の配置は A1    A12    A123 AB1 AB12 AB123 HD167 SDM12 WB987 の組み合わせです。 (アルファベットと数字はそれぞれまとまっていて、入り混じることはありません) これを、   A  B  C   1 A1  A   1 2 A12 A 12 3 A123 A 123 4 AB1 AB 1 のように、アルファベットと数字を別々にセルに置き換えたいのです。 マクロを使わず、B列以降のセルを使って関数でできないでしょうか? よろしくお願いいたします。

  • 半角数字が入ったデータで、半角数字を全角数字に変化関したいのですが

    半角数字が入ったデータで、半角数字を全角数字に変化関したいのですが うまくいきません。 文字コードはUTF-8です。 下記のような、関数を使ってまず半角の1を全角の1に変換しようとしました。 int substitute(unsigned char *s, int n){ int num; num= atoi(s); switch(num) { case '1': s[n] = 0xEF; s[n+1] = 0xBC; s[n+2] = 0x91; s[n+3] = 0x0d; break; defult: break; } return 0; } この関数をかましても半角は全角になりませんでした。 誰か、ご教授願えませんか?

専門家に質問してみよう