switch
(Cで)ステートメントのような構造を書く方法はありますが、文字列用ですか?CでC構文を書く方法はありますか?
C構文とは、中括弧を含むステートメントを意味します...ステートメントに中括弧があるようif
に、それはC構造です...そうですか?
switch
(Cで)ステートメントのような構造を書く方法はありますが、文字列用ですか?CでC構文を書く方法はありますか?
C構文とは、中括弧を含むステートメントを意味します...ステートメントに中括弧があるようif
に、それはC構造です...そうですか?
strcmp
最も単純なアプローチは、比較を行うために使用する if-else チェーンです。
if (strcmp(str, "String 1") == 0)
// do something
else if (strcmp(str, "String 2") == 0)
// do something else
else if (strcmp(str, "String 3") == 0)
// do something else
...
else
printf("%s not found\n", str);
より複雑なアプローチは、文字列をキーとするルックアップ テーブルを使用することです。
struct lookup {const char *key; int value};
struct lookup LookupTable[] = {
{"String 1", 1},
{"String 2", 2},
{"String 3", 3},
...
{NULL, -1}
};
int lookup(const char *key)
{
size_t i = 0;
while (LookupTable[i].key != NULL)
if (strcmp(str, LookupTable[i].key) == 0)
return LookupTable[i].value;
else
i++;
return -1;
}
...
switch(lookup(str))
{
case 1: ...
case 2: ...
case 3: ...
...
default: printf("%s not found\n", str); break;
}
本当に凝ったものにしたい場合は、ルックアップ テーブルを変更して、値が関数へのポインターになるようにすることができます。
void String1Cmd(void) { ... }
void String2Cmd(void) { ... }
void String3Cmd(void) { ... }
...
void BadCmd(void) { printf("Key not found!\n"); }
struct lookup {char *key, void (*cmd)(void); };
struct lookup LookupTable[] = {
{"String 1", String1Cmd},
{"String 2", String2Cmd},
{"String 3", String3Cmd},
...
{NULL, BadCmd}
};
void (*lookup(const char *str))(void)
{
size_t i = 0;
while(LookupTable[i].key != NULL)
if (strcmp(str, LookupTable[i].key) == 0)
return LookupTable[i].cmd;
else
i++;
return BadCmd;
}
...
void (*f)(void) = lookup(str); // retrieve the function for the given string
f(); // execute the function
最後の例では、if str
== "String 1" の場合、String1Cmd
実行されます。str
検索テーブルに文字列が見つからない場合は、BadCmd
が実行されます。この方法は非常に柔軟で、設計によっては、実行時に動作を追加できます (一種のプラグイン アーキテクチャ)。
ただし、主な問題 (文字列値での分岐) をlookup
関数に延期しただけであり、関数はテーブル内の各値に対してlookup
実行するだけに戻っていることに注意してください。ハッシュテーブルまたはツリーを使用して比較の数を最小限に抑えることstrcmp
で、プロセスのその部分を高速化できます。分岐している文字列の数に応じて、追加の作業に値する場合とそうでない場合があります。
いいえ、自分で行う必要があります。多くのバリエーションがあります:
if (strcmp(str, "toto") == 0)
{
// ...
}
else if (strcmp(str, "tata") == 0)
{
// ...
}
else
{
// ...
}
文字列の数が増えると予想される場合は、関数ポインタを含むディスパッチ テーブル
struct dispatch_entry
{
const char *key;
void (*action)(void);
};
// Make sure it is sorted !
dispatch_entry dispatch_table[] =
{
{ "tata", &action_tata },
{ "toto", &action_toto },
};
二分探索と組み合わせる:
int dispatch_compare(const void *x, const void *y)
{
const dispatch_entry *xx = x, *yy = y;
return strcmp(xx->key, yy->key);
}
// Return -1 on failure
int dispatch(const char *str)
{
static const size = sizeof(struct dispatch_entry);
static const n = sizeof(dispatch_table) / size ;
dispatch_entry tmp = { str, NULL };
dispatch_entry *what = bsearch(tmp, dispatch_table, n, size, &dispatch_compare);
if (what == NULL) return -1;
(*what->action)();
return 0;
}
しましょう。ハッシュテーブルベースのアプローチもOKです。
lib(POSIXまたはgcc)に関数lfindがある場合は、次のように使用できます。
enum { NOTFOUND, HELLO, WORLD, FOO, BAR };
char list[][100]={"hello","world","foo","bar"};
size_t r, siz = sizeof*list, num = sizeof list/siz;
char *tosearch = "foo";
switch ( (r=lfind(tosearch,list,&num,siz,strcmp))?
(r+siz-(size_t)list)/siz:0 ) {
case HELLO: puts("hello");break;
case WORLD: puts("world");break;
case FOO: puts("foo"); break;
case BAR: puts("bar"); break;
case NOTFOUND:puts("not found");
}
配列内の各文字列は同じサイズでなければならず、ポインタであってはなりません
文字列の数が多く、速度が問題になる場合はハッシュテーブル
いいえ、スイッチは一体型または一体型に変換可能なタイプでのみ使用できます。
はい、そしてその方法は-長いif-else-if
声明です。(参考:switchステートメントを文字列に適用できないのはなぜですか?)
そして、「CのCコンストラクト」とはどういう意味ですか?あなたが答えたら、私は私の投稿を編集します:)
もちろん、あなたがどれだけの仕事をしたいかによります。
プリプロセッサといくつかのマクロを使用して、文字列を整数識別子にマップすると、次のような構文が得られます。
switch (SOSID_LOOKUP (sample_string)) {
case SOSID (hello): printf ("Hello "); break;
case SOSID (world): printf ("World! "); break;
case 0: default: printf ("unknown "); break;
}
C の代わりに C++ を使用できる場合は、litb の テンプレート ベースの string switcher を使用して、次のような構文を使用できます。
sswitch(s) {
scase("foo"): {
std::cout << "s is foo" << std::endl;
break; // could fall-through if we wanted
}
// supports brace-less style too
scase("bar"):
std::cout << "s is bar" << std::endl;
break;
// default must be at the end
sdefault():
std::cout << "neither of those!" << std::endl;
break;
}
いいえ、switch
整数値で動作します (float/double も許可されていないと思います)。if/else if/else doing でそれをエミュレートできますstrcmp
。
if (strcmp(mystr, "this") == 0) {
//mystr == "this"
}
else if (strcmp(mystr, "that") == 0) {
//mystr == "that"
}
else {
//mystr is not "this" or "that"
}