- ベストアンサー
sscanfでフォーマットに合っているかを調べるには。
今,Cの関数で0-9,A-Zの4文字以内の文字列かどうか を調べたいのですが, int main() { int i; char str[] = "ABCD" /* 調べたい文字列1 */ char str1[]= "ABC@" /* 調べたい文字列1 */ char str2[]= "ABCDE" /* 調べたい文字列1 */ char *p; p = str; /* ここをstr1,str2に変える */ if (strlen(p) != 4) printf("エラーです\n"); for (i = 0; i < 4; i++) { if (!isupper(p[i]) && !isdigit(p[i])) { printf("えらーです\n"); return EXIT_FAILURE; } } printf("すべてOKです\n"); return EXIT_SUCCESS; } というようにすれば,strとstr1とstr2がフォーマットに合うかわかるのですが,これをsscanfの正規表現を使用して実装したいのですが,可能でしょうか。 int main() { int ret; char str[] = "ABCD" /* 調べたい文字列1 */ char str1[]= "ABC@" /* 調べたい文字列1 */ char str2[]= "ABCDE" /* 調べたい文字列1 */ char *p; chat tmp[30]; p = str; ret = sscanf(p, "%4[0-9A-Z]", tmp); if (ret != 1) { printf("エラーです\n"); return EXIT_FAILURE; } printf("すべてOKです\n"); return EXIT_SUCCESS; } といしょうとするならば,str1のときは,@までのABCの文字列がとれて,retには1が帰ってきてしまいます。 なにか4文字以内ということを実装できる正規表現の使い方はあるのでしょうか? ちなみに sscanf(str, "%1[0-9A-Z]%1[0-9A-Z]%1[0-9A-Z]%1[0-9A-Z]", tmp1, tmp2, tmp3, tmp4) という以外でわかる方,よろしくおねがいします。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
#1です。 #2さんの書かれている事はもっともで、私もscanfを使っている質問者に対しては、「scanfは初心者は絶対使ってはいけない関数」といつも答えてます。初心者で無くてもキーボード入力に対しては使わないほうがよいでしょう。 ファイルからの読み取りに関しては中上級者でも、各種イリーガルなデータに対する十ニ分なテストが必要です。 sscanfはこれらに比べると行を跨った問題が起こらず、どこからスキャンを始めるかも明確なので比較的使いやすいと思います。fgetsした1行の解析もatoi等だけで済めばいいですが、複雑な場合はsscanfの力を借りるのもいいでしょう。ただ、sscanfを使うならマニュアルの熟読が必要です。 #1に書いたのと別の解法としては、 int n; n=0; sscanf(p,"%29[0-9A-Z]%n",tmp,&n); とすると、nに英数字部分の長さが入ります(29はtmpのサイズに合わせる)。英数字部分が先頭に無い場合はnには何も代入されないので、0で初期化しておきます。 チェックのためだけでtmp[]に値をセットする必要は無いのなら、下記のように*で代入を抑止すると、tmp変数が不要になり、tmpのサイズを気にする必要も無くなります。 sscanf(p,"%*[0-9A-Z]%n",&n); 実行速度についてはこのケースでは#2さんの通り、sscanfを使わないほうが速いと思います。
その他の回答 (2)
- shige_70
- ベストアンサー率17% (168/946)
余計なお世話的なアドバイスをします。気に入らなければ無視してください。 もっと複雑な文字列スキャンを実装したいのならともかく、4文字以内の大文字英数という程度の条件だったら、質問文前半にあるように1文字ずつ調べた方が早い(速い)です。 わざわざsscanf()を用いる理由は、学習のためでしょうか? だったらなおさら無駄です。そもそもscanf()系関数は複雑怪奇な仕様で、バグの温床になりやすく、安易に使用すべきではないのです。 上記のことから、ご質問のような実装は推奨できません。 ちなみに、scanf()系関数のフォーマットの %[ は、正規表現とは違いますので、混同されませんように。。。
- notnot
- ベストアンサー率47% (4900/10358)
int tmp2; を追加して、 ret = sscanf(p, "%4[0-9A-Z]%c", tmp,&tmp2); でどうでしょうか。 5文字以上あれば、5文字目がtmp2に入って、retが2になる。