如何使用“switch”语句比较 C 中的字符串?
在 C 中,有一个 switch
结构,它使人们能够根据测试整数值执行不同的条件代码分支,例如,
int a;
/* Read the value of "a" from some source, e.g. user input */
switch (a) {
case 100:
// Code
break;
case 200:
// Code
break;
default:
// Code
break;
}
如何才能获得相同的行为(即避免所谓的“ if
-else
ladder") 对于字符串值,即 char *
?
In C there is a switch
construct which enables one to execute different conditional branches of code based on an test integer value, e.g.,
int a;
/* Read the value of "a" from some source, e.g. user input */
switch (a) {
case 100:
// Code
break;
case 200:
// Code
break;
default:
// Code
break;
}
How is it possible to obtain the same behavior (i.e. avoid the so-called "if
-else
ladder") for a string value, i.e., a char *
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
我首选的方法是通过哈希函数(借自此处)。即使在使用 char * 时,这也允许您利用 switch 语句的效率:
当然,这种方法要求提前计算所有可能接受的 char * 的哈希值。我不认为这是一个太大的问题;但是,由于 switch 语句无论如何都对固定值进行操作。可以编写一个简单的程序来将 char * 传递给哈希函数并输出它们的结果。然后可以像我上面所做的那样通过宏定义这些结果。
My preferred method for doing this is via a hash function (borrowed from here). This allows you to utilize the efficiency of a switch statement even when working with char *'s:
Of course, this approach requires that the hash values for all possible accepted char *'s are calculated in advance. I don't think this is too much of an issue; however, since the switch statement operates on fixed values regardless. A simple program can be made to pass char *'s through the hash function and output their results. These results can then be defined via macros as I have done above.
我认为最好的方法是将“识别”与功能分开:
I think the best way to do this is separate the 'recognition' from the functionality:
我发布了一个 头文件 来对 C 中的字符串执行切换。它包含一组隐藏对 strcmp() (或类似)的调用的宏,以模仿类似开关的行为。
我只在 Linux 中使用 GCC 对其进行了测试,但我确信它可以适应其他环境。
编辑:根据要求在此处添加代码
这是您应该包含的头文件:
这就是您使用它的方式:
请注意每个 后面没有冒号(':') case 也不在默认值之后。
I have published a header file to perform the switch on the strings in C. It contains a set of macro that hide the call to the strcmp() (or similar) in order to mimic a switch-like behaviour.
I have tested it only with GCC in Linux, but I'm quite sure that it can be adapted to support other environment.
EDIT: added the code here, as requested
This is the header file you should include:
And this is how you use it:
Please notice that there is no colon (':') after each case nor after the defaults.
有一种方法可以更快地执行字符串搜索。假设:由于我们正在讨论 switch 语句,我可以假设这些值在运行时不会改变。
这个想法是使用 C stdlib 的 qsort 和 bsearch。
我将研究 xtofl 的代码。
There is a way to perform the string search faster. Assumptions: since we are talking about a switch statement, I can assume that the values won't be changing during runtime.
The idea is to use the C stdlib's qsort and bsearch.
I'll be working on xtofl's code.
要添加到 Phimueme 上面的答案,如果您的字符串始终是两个字符,那么您可以从两个 8 位字符构建一个 16 位 int - 并打开它(以避免嵌套 switch/case 语句)。
To add to Phimueme's answer above, if your string is always two characters, then you can build a 16-bit int out of the two 8-bit characters - and switch on that (to avoid nested switch/case statements).
为了将一个字符串与其他字符串进行比较,我们无法逃避 if-else 梯子。即使是常规的 switch-case 内部也是一个 if-else 梯子(对于整数)。我们可能只想模拟字符串的 switch-case,但永远无法替代 if-else 梯子。最好的字符串比较算法都离不开使用 strcmp 函数。意思是逐个字符进行比较,直到发现不匹配为止。所以使用 if-else 梯子和 strcmp 是不可避免的。
DEMO
这里是模拟字符串 switch-case 的最简单的宏。
您可以将它们用作
输出:
下面是嵌套 SWITCH 用法:
输出:
这是反向字符串 SWITCH,其中您可以在 CASE 子句中使用变量(而不是常量):
输出:
We cannot escape if-else ladder in order to compare a string with others. Even regular switch-case is also an if-else ladder (for integers) internally. We might only want to simulate the switch-case for string, but can never replace if-else ladder. The best of the algorithms for string comparison cannot escape from using strcmp function. Means to compare character by character until an unmatch is found. So using if-else ladder and strcmp are inevitable.
DEMO
And here are simplest macros to simulate the switch-case for strings.
And you can use them as
Output:
Below is nested SWITCH usage:
Output:
Here is reverse string SWITCH, where in you can use a variable (rather than a constant) in CASE clause:
Output:
如果它是 2 字节字符串,您可以执行类似于此具体示例中的操作,其中我打开了 ISO639-2 语言代码。
LANIDX_* 是用于在数组中索引的常量整数。
If it is a 2 byte string you can do something like in this concrete example where I switch on ISO639-2 language codes.
LANIDX_* being constant integers used to index in arrays.
我一般都是这样做的。
This is generally how I do it.
这就是你的做法。不,不是真的。
宏依赖于编译器扩展,否则您可能会收到
'open'
是一个多字符字符常量,其值取决于实现。This is how you do it. No, not really.
Macro relies on a compiler extension else you may receive
'open'
is a multi-character character constant and its value is implementation dependent.假设小字节序和
sizeof(char) == 1
,你可以这样做(建议这样做)这个答案)。它可以推广到 BE 情况。
Assuming little endianness and
sizeof(char) == 1
, you could do that (something like this was suggested by this answer).It could be generalized for BE case.
函数指针是实现此目的的好方法,例如
result = switchFunction(someStringKey); //结果是一个可选的返回值
...这调用您通过字符串键设置的函数(每种情况一个函数):
使用预先存在的哈希图/表/字典实现,例如 khash,返回该函数指向 switchFunction() 内部函数的指针,并执行它(或者直接从 switchFunction() 返回它并自己执行)。如果地图实现不存储它,只需使用
uint64_t
而不是相应地转换为指针。Function pointers are a great way to do this, e.g.
result = switchFunction(someStringKey); //result is an optional return value
...this calls a function that you have set by string key (one function per case):
Use a pre-existing hashmap/table/dictionary implementation such as khash, return that pointer to a function inside of
switchFunction()
, and execute it (or just return it fromswitchFunction()
and execute it yourself). If the map implementation doesn't store that, just use auint64_t
instead that you cast accordingly to a pointer.如果您遇到这种情况,这是简单快捷的方法:
说明:
例如,如果我有很多菜单,第一个菜单上的每个选项都会将您带到第二个菜单,第二个菜单到第三个菜单,依此类推。但选项不同。
你知道用户终于合唱了。示例:
菜单 1:1 ->菜单 2:4 ->菜单3:2
选择为142。其他情况:111、141、131、122...
解决方法:
第一个存储在 A 中,第二个存储在 B 中,第三个存储在 C 中。
This is the easy and fast way if you have this case:
Explanation:
For example, if I have many menus, each choice on the 1st menu takes you to the 2nd menu, the 2nd to the 3rd menu, and so on. But the Options are different.
You know that the user has chorused finally. Example:
Menu 1: 1 -> Menu 2: 4 -> Menu 3: 2
The choice is 142. Other cases: 111, 141, 131, 122 ...
Solution:
Store the first 1st in A, 2nd in B, 3rd in C.
如果你的意思是,如何编写类似的东西:
那么 C 中的规范解决方案是使用 if-else 梯子:
If you mean, how to write something similar to this:
Then the canonical solution in C is to use an if-else ladder:
如果您有很多情况并且不想编写大量
strcmp()
调用,您可以执行以下操作:您只需确保哈希函数在可能值集中没有冲突对于字符串。
If you have many cases and do not want to write a ton of
strcmp()
calls, you could do something like:You just have to make sure your hash function has no collisions inside the set of possible values for the string.
在 C 中没有办法做到这一点。有很多不同的方法。通常,最简单的方法是定义一组表示字符串的常量,并按字符串进行查找以获取常量:
当然,有更有效的方法可以做到这一点。如果您对键进行排序,则可以使用二分搜索。您也可以使用哈希表。这些事情会改变你的性能,但会牺牲维护成本。
There is no way to do this in C. There are a lot of different approaches. Typically the simplest is to define a set of constants that represent your strings and do a look up by string on to get the constant:
There are, of course, more efficient ways to do this. If you keep your keys sorted, you can use a binary search. You could use a hashtable too. These things change your performance at the expense of maintenance.