使用不区分大小写的字符串比较函数代替<
运算符。
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
命令已经自带排序,但与基于语言环境的排序不完全相同。
如果您想将一些用户输入的任意字符串按照用户直接看到的顺序进行排序,则通常需要使用区域设置感知字符串比较。只有大小写或重音符号不同的字符串才不会相等,因此如果您使用稳定排序并依赖于大小写不同的字符串相等,则这种方法行不通,但是在其他情况下可以得到很好的结果。根据使用情况,比普通的不区分大小写的比较更好。
FreeBSD's strcoll对于除POSIX(ASCII)之外的语言环境仍然区分大小写。那篇论坛帖子表明,在大多数其他系统上它是不区分大小写的。
MSVC 提供了一个 _stricoll
来进行不区分大小写的排序,这意味着它的普通 strcoll
是区分大小写的。然而,这可能只是意味着在等价类内部比较时不会回退。也许有人可以使用 MSVC 测试以下示例。
#include <stdio.h>
#include <locale.h>
int main()
{
const char * s[] = { "FooBar - abc", "Foobar - bcd", "FooBar - cde" };
#ifdef USE_LOCALE
setlocale(LC_ALL, "");
#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。
请参见此帖子以了解strcasecmp的可移植性问题,例如Windows。请参见该问题的其他答案以了解其他C++进行大小写不敏感字符串比较的方法。
一旦您拥有了一个不区分大小写的比较函数,就可以将其与其他排序算法一起使用,例如C标准库中的
qsort
或c ++
std :: sort,而无需编写自己的O(n^2)选择排序。
正如b.buchhold的回答指出的那样,在运行时进行不区分大小写的比较可能比将所有内容转换为小写一次,并对索引数组进行排序要慢。需要多次使用每个字符串的小写版本。
std :: strxfrm将转换一个字符串,使得对结果进行
strcmp
将得到与对原始字符串进行
strcoll
相同的结果。