使用不区分大小写的字符串比较函数,而不是 < 运算符。
C89/C99 提供strcoll(字符串整理),它进行区域感知字符串比较。它在 C++ 中以std::strcoll 的形式提供。在某些(大多数?)语言环境中,例如 en_CA.UTF-8、A 和 a(以及它们的所有重音形式)属于同一个等价类。我认为 strcoll 仅在整个字符串相等的情况下才在等价类中作为平局进行比较,这与不区分大小写的比较提供了非常相似的排序顺序。排序规则(至少在 GNU/Linux 上的英语语言环境中)会忽略某些字符(例如 [)。所以ls /usr/share | sort 给出的输出类似于
acpi-support
adduser
ADM_scripts
aglfn
aisleriot
我通过sort 进行管道传输,因为ls 进行自己的排序,这与sort 基于区域设置的排序不太一样。
如果您想将一些用户输入的任意字符串排序为用户可以直接看到的顺序,那么通常需要进行区域感知的字符串比较。仅在大小写或重音上不同的字符串不会比较相等,因此如果您使用稳定的排序并依赖于区分大小写的字符串来比较相等,那么这将不起作用,但否则您会得到很好的结果。根据用例,比普通的不区分大小写的比较更好。
FreeBSD's strcoll 对于 POSIX (ASCII) 以外的语言环境过去和现在可能仍然区分大小写。该论坛帖子表明,在大多数其他系统上,它不区分大小写。
MSVC 为不区分大小写的排序规则提供_stricoll,这意味着其正常的strcoll 是区分大小写的。但是,这可能只是意味着不会发生在等价类中进行比较的回退。也许有人可以用 MSVC 测试以下示例。
// strcoll.c: show that these strings sort in a different order, depending on locale
#include <stdio.h>
#include <locale.h>
int main()
{
// TODO: try some strings containing characters like '[' that strcoll ignores completely.
const char * s[] = { "FooBar - abc", "Foobar - bcd", "FooBar - cde" };
#ifdef USE_LOCALE
setlocale(LC_ALL, ""); // empty string means look at env vars
#endif
strcoll(s[0], s[1]);
strcoll(s[0], s[2]);
strcoll(s[1], s[2]);
return 0;
}
gcc -DUSE_LOCALE -Og strcoll.c && ltrace ./a.out 的输出(或运行 LANG=C ltrace a.out):
__libc_start_main(0x400586, 1, ...
setlocale(LC_ALL, "") = "en_CA.UTF-8" # my env contains LANG=en_CA.UTF-8
strcoll("FooBar - abc", "Foobar - bcd") = -1
strcoll("FooBar - abc", "FooBar - cde") = -2
strcoll("Foobar - bcd", "FooBar - cde") = -1
# the three strings are in order
+++ exited (status 0) +++
gcc -Og -UUSE_LOCALE strcoll.c && ltrace ./a.out:
__libc_start_main(0x400536, ...
# no setlocale, so current locale is C
strcoll("FooBar - abc", "Foobar - bcd") = -32
strcoll("FooBar - abc", "FooBar - cde") = -2
strcoll("Foobar - bcd", "FooBar - cde") = 32 # s[1] should sort after s[2], so it's out of order
+++ exited (status 0) +++
POSIX.1-2001 提供strcasecmp。但是,POSIX 规范说,对于普通 ASCII 以外的语言环境,结果是“未指定的”,所以我不确定常见的实现是否正确处理 utf-8。
见this post for portability issues with strcasecmp, e.g. to Windows。有关进行不区分大小写字符串比较的其他 C++ 方法,请参阅该问题的其他答案。
一旦有了不区分大小写的比较函数,就可以将它与其他排序算法一起使用,例如 C 标准库 qsort 或 c++ std::sort,而不是编写自己的 O( n^2) 选择排序。
正如 b.buchhold 的回答所指出的,即时进行不区分大小写的比较可能比将所有内容都转换为小写一次并对索引数组进行排序要慢。每个字符串的小写版本需要多次。 std::strxfrm 将转换一个字符串,以便结果上的strcmp 将给出与原始字符串上的strcoll 相同的结果。