根据标准:
执行字符集的成员值是实现定义的 (ISO / IEC 9899:1999 5.2.1 / 1)
进一步在标准中:
...上述小数位数列表中
0
之后的每个字符的值应大于前一个值。
(ISO / IEC 9899:1999 5.2.1 / 3)
标准似乎要求执行字符集包括拉丁字母的26个大写字母和26个小写字母,但我认为不要求以任何方式对这些字符进行排序。我只看到十进制数字的订单规定。
这似乎意味着,严格来说,不能保证'a' < 'b'
。现在,字母表中的字母按顺序分为ASCII,UTF-8和EBCDIC。但是对于ASCII和UTF-8,我们有'A' < 'a'
,而对于EBCDIC,我们有'a' < 'A'
。
在ctype.h
中有一个可以移植地比较字母字符的函数可能会很好。如果没有这个或类似的东西,在我看来,必须在区域设置中查找CODESET
的值并相应地继续,但这似乎并不简单。
我的直觉告诉我,这几乎不是问题;对于大多数情况,字母字符可以通过转换为小写来处理,因为对于最常用的字符集,字母是有序的。
问题:给出两个字符
char c1;
char c2;
是否有一种简单,可移植的方式来确定c1
是否按字母顺序排在c2
之前?或者我们是否假设小写和大写字符总是按顺序出现,即使标准似乎没有保证这一点?
为了澄清任何混淆,我真的只对拉丁字母的52个字母感兴趣,这些字母由标准保证在执行字符集中。我意识到其他字母组很重要,但似乎我们甚至无法知道这一小部分字母的排序。
我认为我需要澄清一点。我认为,问题在于我们通常认为拉丁字母的26个小写字母是有序的。我希望能够断言“a”出现在'b'之前,当我们给出'a'和'b'整数值时,我们有一种方便的方式在代码中表达'a' < 'b'
。但该标准不保证上述代码将按预期进行评估。为什么不?该标准确实保证了数字0-9的这种行为,这似乎是明智的。如果我想确定一个字母字符是否在另一个字母之前,比如用于排序目的,并且如果我希望这个代码真正可移植,那么标准似乎没有帮助。现在我必须依赖ASCII,UTF-8,EBCDIC等采用'a' < 'b'
应该为真的惯例。但是,除非使用的唯一字符集依赖于此约定,否则这不是真正可移植的;这可能是真的。
这个问题源于另一个问题主题:Check if a letter is before or after another letter in C。在这里,一些人建议你可以使用不等式来确定char
中存储的两个字母的顺序。但是一位评论者指出,标准并不保证这种行为。
答案 0 :(得分:10)
strcoll就是为此目的而设计的。只需设置两个字符串,每个字符串一个字符。 (通常你想比较字符串,而不是字符)。
答案 1 :(得分:6)
历史上使用的代码不是简单地命令字母表。例如,Baudot将元音放在辅音之前,所以&#39; A&#39; &LT; &#39; B&#39;,但&#39; U&#39; &LT; &#39; B&#39;同样。
还有像EBCDIC这样的代码是有序的,但有差距。所以在EBCDIC中,我是&#39; &LT; &#39; J&#39;,但是&#39;我&#39; + 1!=&#39; J&#39;。
答案 2 :(得分:6)
你可能只是为ASCII字符数字的标准保证字符制作一个表格。如,
#include <limits.h>
static char mytable[] = {
['a'] = 0x61,
['b'] = 0x62,
// ...
['A'] = 0x41,
['B'] = 0x42,
// ...
};
编译器会将当前字符集中的每个字符(可能是任何疯狂的字符集)映射到ASCII码,并且不保证存在的字符将映射到零。然后您可以在需要时使用此表进行排序。
正如你所说,
char c1;
char c2;
通过检查
可以按字母顺序验证(c1 < sizeof(mytable) && c2 < sizeof(mytable) ? mytable[c1] < mytable[c2] : 0)
我实际上在一个研究项目中使用了这个项目,该项目运行在ASCII和EBCDIC上以实现可预测的排序,但它的可移植性足以处理任何字符集。 编辑:我实际上让表的大小为空,以便计算到所需的最小值,因为DeathStation 9000,一个字节可能有32位,因此CHAR_MAX
最高可达4294967295。
答案 3 :(得分:4)
对于A-Z,a-z
,不区分大小写(并使用复合文字):
char ch = foo();
az_rank = strtol((char []){ch, 0}, NULL, 36);
对于2 char
已知为A-Z,a-z但可能是ASCII或EBCDIC。
int compare2alpha(char c1, char c2) {
int mask = 'A' ^ 'a'; // Only 1 bit is different between upper/lower
return (c1 | mask) - (c2 | mask);
}
或者,如果限制为256个char
,则可以使用将char
映射到其排名的查找表。当然,该表与平台有关。
答案 4 :(得分:2)
使用C11,代码可以使用_Static_assert()
来确保在编译时时,字符具有所需的顺序。
这种方法的一个优点是,由于压倒性的字符编码都准备好满足所需的AZ要求,如果一个新颖或深奥的平台使用不同的东西,它可能需要编码或定制不是可预见的。在这种情况下,这个最好的代码就是无法编译。
使用示例
// Sample case insensitive string sort routine that insures
// 1) 'A' < 'B' < 'C' < ... < 'Z'
// 2) 'a' < 'b' < 'c' < ... < 'z'
int compare_string_case_insensitive(const void *a, const void *b) {
_Static_assert('A' < 'B', "A-Z order unexpected");
_Static_assert('B' < 'C', "A-Z order unexpected");
_Static_assert('C' < 'D', "A-Z order unexpected");
// Other 21 _Static_assert() omitted for brevity
_Static_assert('Y' < 'Z', "A-Z order unexpected");
_Static_assert('a' < 'b', "a-z order unexpected");
_Static_assert('b' < 'c', "a-z order unexpected");
_Static_assert('c' < 'd', "a-z order unexpected");
// Other 21 _Static_assert() omitted for brevity
_Static_assert('y' < 'z', "a-z order unexpected");
const char *sa = (const char *)a;
const char *sb = (const char *)b;
int cha, chb;
do {
cha = toupper((unsigned char) *sa++);
chb = toupper((unsigned char) *sb++);
} while (cha && cha == chb);
return (cha > chb) - (cha < chb);
}