- 締切済み
文字の探索について
文字列中の英大文字,英小文字の出現回数をカウントし、その回数を出力するプログラムを作りたいのですが、どうもうまく動いてくれません。 ABC123Abcのときの出力結果は 'A' = 2 'B' = 1 'C' = 1 'D' = 0 'E' = 0 中略 'X' = 0 'Y' = 0 'Z' = 0 'a' = 0 'b' = 1 'c' = 1 中略 'y' = 0 'z' = 0 のように出したいです。 私が考えた方法では まず文字列を配列str[100]に読み込み for文で、'\0'が来るまで配列の中身の文字を一つずつ判定('A'が見つかると、変数Aの値をを1つ増やす)していき、 全ての文字の判定後、 printf("'A' = %d\n", A); printf("'B' = %d\n", B); 中略 printf("'z' = %d\n", z); という風に表示しようとしたのですが、うまく表示されず、プログラム自体もとても長くなってしまい、これが正解とはいえない状態です。 こんな方法よりもっといい方法があれば教えていただきたいです。 あと、判定方法もお願いします・・・。
- みんなの回答 (9)
- 専門家の回答
みんなの回答
- Tacosan
- ベストアンサー率23% (3656/15482)
いんちきそのものは「結果を出力したい文字の一覧」を持てば逃げられますね>#8. ちなみに c を unsigned char にすればより安全.
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
C言語のいろいろな特性があり、こんなプログラムにすることもできます。 #include <cstdio> int main() { int count[256] = {0}; // 256 個というのは、普通の処理系では、char が収まる範囲 char *input = "ABC123Abc"; for (int i = 0; input[i] != '\0'; i++) { char c = input[i]; // 1文字切り出して count[c]++; // その文字に相当するカウンタ(配列で準備)を+1 } for (char c = 'A'; c <= 'Z'; c++) { // char なら普通にループのインデックスにもできる std::printf(" '%c' = %d\n", c, count[c]); } for (char c = 'a'; c <= 'z'; c++) { std::printf(" '%c' = %d\n", c, count[c]); } return 0; } 気分はわかりやすいと思います。 これは、C言語では、char 型は実は整数型でもあるという性質を使っています。 ただし、このコードは文字コードが連続していると言うことを前提にしていたりして、ちょっとインチキではありますが。
- yama5140
- ベストアンサー率54% (136/250)
>'A'が見つかると、変数A(●)の値をを1つ増やす ・(略) >判定方法もお願いします・・・(◆) ★初めに、参考URLにアスキーコード表を示します。 文字 A ~ Z は、アスキーコードで 0x41 ~ 0x5A に連続して対応します。 文字 a ~ z は、アスキーコードで 0x61 ~ 0x7A に連続して対応します。 文字 0 ~ 9 は、アスキーコードで 0x30 ~ 0x39 に連続して対応します。 ☆これらの出現回数を格納する配列(●)を用意し、初期化します。 int iCntBig[26] = { 0 }; // A ~ Z用 int iCntSml[26] = { 0 }; // a ~ z用 int iCntDig[10] = { 0 }; // 0 ~ 9用 ☆対象となる文字列長(文字列読込み後) int iLen = strlen( cMojiRetsu ); ★出現を判定し、その回数をカウント(◆) for( i = 0; i < iLen; i++ ){ if( isupper( cMojiRetsu[i] ) ) iCntBig[ cMojiRetsu[i] - 0x41 ]++; if( islower( cMojiRetsu[i] ) ) iCntSml[ cMojiRetsu[i] - 0x61 ]++; if( isdigit( cMojiRetsu[i] ) ) iCntDig[ cMojiRetsu[i] - 0x30 ]++; } ★出現回数を表示 for( i26 = 0; i26 < 26; i26++ ){ printf( "'%c'=%3d\n", ( i26 + 0x41 ), iCntBig[i26] ); } for( i26 = 0; i26 < 26; i26++ ){ printf( "'%c'=%3d\n", ( i26 + 0x61 ), iCntSml[i26] ); } for( i10 = 0; i10 < 10; i10++ ){ printf( "'%c'=%3d\n", ( i10 + 0x30 ), iCntDig[i10] ); } 注:表現上、全角空白を用いています。 ★プログラムは10人いれば10種の・・、年寄りが作ると・・↑です。
- melkattz
- ベストアンサー率0% (0/0)
strchr関数を使うのはどうでしょう? #include <stdio.h> int moji_cnt(char *,char); int main(){ char tbl[]={ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z' }; char str[256]="ABC123Abc"; int i; for(i=0;i<52;++i){ fprintf(stdout,"%c=%d\n",tbl[i],moji_cnt(str,tbl[i])); } return 0; } /* 引数1で渡された文字列の中に引数2で渡された文字の 文字数をカウントする */ int moji_cnt(char *str,char moji){ int moji_cnt=0; while(1){ if((str=strchr(str,moji))!=NULL) { ++moji_cnt; ++str; }else{ break; } } return moji_cnt; }
- Oh-Orange
- ベストアンサー率63% (854/1345)
★配列を使っていないでしょ。 >プログラム自体もとても長くなってしまい… ↑ これはA~Zのカウンタに配列を利用すればもっと短くなる気がします。 今はAカウンタ、Bカウンタ、…Zカウンタ、aカウンタ、…zカウンタとしているのかな。 この方法だとプログラムが複雑になると思うため例え正しく動作しても私なら不正解とします。 >うまく表示されず、これが正解とはいえない状態です。 ↑ 動作がおかしいのですか? 考え方としてはあっているように思います。 問題は配列を使っていないため複雑になりすぎているだけでは? ・ASCIIコードのように文字コードが連続している場合には配列と文字判定関数を 組み合わせることでシンプルかつ、分かりやすくなります。 >あと、判定方法もお願いします・・・。 ↑ 判定方法は ctype.h ヘッダにある ・isupper()関数で英大文字を判別 ・islower()関数で英小文字を判別 できます。 これを踏まえてサンプルを載せます。 提示したサンプルが理解できたかどうかを補足に書いて下さい。 待っています。 サンプル: #include <ctype.h> #include <stdio.h> // メイン関数 int main( void ) { char str[ 100 ] = "ABC123Abc"; ←対象の文字列 int count[ 256 ] = { 0 }; ←これが出現回数のカウンタ int i, c; // '\0'が来るまで配列の中身の文字を一つずつ判定 for ( i = 0 ; str[i] != '\0' ; i++ ){ if ( isupper(str[i]) ) count[ str[i] ] += 1; ←英大文字の判別とカウント if ( islower(str[i]) ) count[ str[i] ] += 1; ←英小文字の判別とカウント if ( isdigit(str[i]) ) count[ str[i] ] += 1; ←数字文字の判別とカウント(おまけ) } // 出現回数の結果表示 for ( c = 'A' ; c <= 'Z' ; c++ ) printf( "'%c' = %d回\n", c, count[c] ); ←英大文字の出現回数 for ( c = 'a' ; c <= 'z' ; c++ ) printf( "'%c' = %d回\n", c, count[c] ); ←英小文字の出現回数 for ( c = '0' ; c <= '9' ; c++ ) printf( "'%c' = %d回\n", c, count[c] ); ←数字文字の出現回数(おまけ) return 0; } おまけとして『数字文字の出現回数』も付けています。 1バイト・コードのすべての出現回数をカウントできる count[] 配列を用意しています。 もちろん必要な分だけの配列でも良いですが 256 個しかないので処理を簡単にするために int count[ 256 ] = { 0 }; としています。 また、宣言と同時に初期化しています。これで count[] 配列のすべてがゼロにセットされます。 それでは頑張って下さい。
- kokorone
- ベストアンサー率38% (417/1093)
<うまく表示されず 正常な結果が得られない理由はどこにあるのか、まずは明確にすべきです。そのためには、どのような結果になるのか例示してほしかったですね。 プログラムを改良するのは2の次です。 私の作成したサンプルです。 ポイント:2次元配列、if文未使用 即興で作成したので、エラーになるかも。。 char in_chr[100]; char out_chr[2][26]; int out_cnt[2][26]; int cnt1: int cnt2: int cnt3: int chk_chr; int idx1: int idx2: for(cnt1=0;cnt1<2;cnt1 ++){ for(cnt2=0;cnt2<26;cnt2 ++){ /* 'A'-'Z','a'-'z' をout_chr[][]に設定 */ out_chr[cnt1][cnt2] = 0x41+cnt2+(0x20 * cnt1); /* out_cnt[][]に0を設定 */ out_cnt[cnt1][cnt2] =0; } } for(cnt3=0;cnt3 < 100;cnt++,){ chk_chr = in_chr[cnt3]; idx1 = chk_chr / 0x61; idx2 = chk_chr - (0x20*idx1 + 0x41); out_cnt[idx1][idx2] ++ } for(cnt1=0;cnt1<2;cnt1 ++){ for(cnt2=0;cnt2<26;cnt2 ++){ printf("'%c'=%d\n",out_chr[cnt1][cnt2],out_chr[cnt1][cnt2]); } }
- f_attck
- ベストアンサー率33% (40/118)
私は、今のままの方が可読性が高くて好きですけどん。 プログラム全体が大きいのは問題ないとして、関数が大きく なったのなら、改善するべきと思います。 #それぞれ機能分割するべきです。 可読性は下がりますがやるんならforで\0まで検索するのは同じで、 カウントに関して変更します。 大文字用の配列と小文字用の配列を作ります。 それで、0x41-0x5aまでが大文字で0x61-0x7aまでが小文字なので ifで判断して配列に代入する。 大文字の場合 (big_char[str[n]-0x40-1])++; 小文字の場合は (big_char[str[n]-0x60-1])++; でどうでしょう? 全体としては for(i=0;i<100;i++) { if ((str[i] > 0x40) && (str[i] < 0x5b)) { (big_char[str[n]-0x40-1])++; } else if ((str[i] > 0x60) && (str[i] < 0x7b)) { (big_char[str[n]-0x60-1])++; } else { // input error } } 結果出力に関しても同じように添え字に0x40+1もしくは0x60+1を 足してループさせれば、大文字と小文字分のprintf2個で終わりかな コンパイルとか実行とかしてないんで、間違ってたらごめんなさいね
- asuncion
- ベストアンサー率33% (2127/6289)
サンプルコードです。 #include <stdio.h> #include <string.h> #include <ctype.h> int main(void) { char str[] = "ABC123Abc"; int count[52] = { 0 }, i; for (i = 0; i < strlen(str); i++) { if (isupper(str[i])) count[str[i] - 'A']++; if (islower(str[i])) count[str[i] - 'a' + 26]++; } for (i = 0; i < 26; i++) printf("'%c' = %d\n", 'A' + i, count[i]); for (i = 0; i < 26; i++) printf("'%c' = %d\n", 'a' + i, count[i + 26]); return 0; } (注)インデントのため、全角空白を使っています。
- Tacosan
- ベストアンサー率23% (3656/15482)
「整数 (0~9) の配列に対して, 各整数がその中にどれだけあるかを数える」プログラムを書いてみてください.