C strcoll 函数
最后修改:2025 年 4 月 8 日
字符串比较在 C 编程中是基础的,而 strcoll
提供了带区域设置感知的比较功能。本教程将深入介绍 strcoll
,包括其语法、用法和区域设置依赖性。我们将探讨实际示例,并讨论何时使用它而不是 strcmp
。理解 strcoll
有助于创建在不同语言设置下都能正确工作的程序。
什么是 strcoll?
strcoll
函数根据当前区域设置比较两个字符串。它声明在 string.h
中,并接受两个字符串指针。与 strcmp
不同,它尊重特定于区域设置的排序规则。strcoll
返回一个整数,指示字符串之间的关系。为了安全起见,当区域设置很重要时,优先使用 strcoll
而不是 strcmp
。
基本的 strcoll 用法
此示例演示了使用 strcoll
进行基本的字符串比较。
#include <stdio.h> #include <string.h> #include <locale.h> int main() { setlocale(LC_ALL, ""); const char *str1 = "apple"; const char *str2 = "banana"; int result = strcoll(str1, str2); if (result < 0) { printf("'%s' comes before '%s'\n", str1, str2); } else if (result > 0) { printf("'%s' comes after '%s'\n", str1, str2); } else { printf("Strings are equal\n"); } return 0; }
在这里,strcoll
按字母顺序比较两个字符串。setlocale
调用初始化程序的区域设置。如果 str1 在 str2 之前,则该函数返回一个负值;如果相等,则返回零;如果 str1 在 str2 之后,则返回一个正值。这个基本示例显示了标准的字母顺序比较行为。
特定于区域设置的比较
此示例显示了 strcoll
在不同区域设置下的行为差异。
#include <stdio.h> #include <string.h> #include <locale.h> int main() { const char *str1 = "äbc"; const char *str2 = "abc"; // Compare with C locale setlocale(LC_ALL, "C"); printf("C locale: %d\n", strcoll(str1, str2)); // Compare with German locale setlocale(LC_ALL, "de_DE.utf8"); printf("German locale: %d\n", strcoll(str1, str2)); return 0; }
此代码演示了区域设置如何影响字符串比较。在 C 区域设置中,带音标的字母(例如 umlauts)的排序可能与德语不同。德语区域设置能够正确处理 'ä',将其视为一个单独的字母,排在 'a' 之后。在使用 strcoll
处理国际文本之前,务必设置适当的区域设置。
使用 strcoll 对字符串进行排序
此示例演示了使用 strcoll
对字符串数组进行排序。
#include <stdio.h> #include <string.h> #include <locale.h> #define COUNT 5 int compare(const void *a, const void *b) { return strcoll(*(const char **)a, *(const char **)b); } int main() { setlocale(LC_ALL, ""); const char *words[COUNT] = {"čaj", "auto", "bůh", "dům", "cedr"}; qsort(words, COUNT, sizeof(char *), compare); printf("Sorted words:\n"); for (int i = 0; i < COUNT; i++) { printf("%s\n", words[i]); } return 0; }
此代码在使用 qsort
的比较函数中,通过 strcoll
正确地对捷克语单词进行了排序。区域设置已设置为系统默认值,这应该可以正确处理捷克语字符。比较函数在传递 strcoll
之前,将 void 指针转换为字符串指针。这种方法适用于任何特定于区域设置的排序。
不区分大小写的比较
此示例显示了如何使用 strcoll
进行不区分大小写的比较。
#include <stdio.h> #include <string.h> #include <locale.h> #include <ctype.h> int strcasecoll(const char *a, const char *b) { char a_lower[256], b_lower[256]; size_t i; for (i = 0; a[i] && i < sizeof(a_lower) - 1; i++) { a_lower[i] = tolower(a[i]); } a_lower[i] = '\0'; for (i = 0; b[i] && i < sizeof(b_lower) - 1; i++) { b_lower[i] = tolower(b[i]); } b_lower[i] = '\0'; return strcoll(a_lower, b_lower); } int main() { setlocale(LC_ALL, ""); const char *str1 = "Zebra"; const char *str2 = "apple"; int result = strcasecoll(str1, str2); if (result < 0) { printf("'%s' comes before '%s'\n", str1, str2); } else if (result > 0) { printf("'%s' comes after '%s'\n", str1, str2); } else { printf("Strings are equal\n"); } return 0; }
此实现创建了 strcoll
的不区分大小写的版本。它首先将字符串转换为小写,然后进行比较。会检查缓冲区大小以防止溢出。请注意,此方法可能无法完美处理所有特定于区域设置的大小写转换。对于生产代码,请考虑更健壮的解决方案。
比较带数值的字符串
此示例演示了 strcoll
如何处理包含数字的字符串。
#include <stdio.h> #include <string.h> #include <locale.h> int main() { setlocale(LC_ALL, ""); const char *versions[] = {"file1.txt", "file10.txt", "file2.txt"}; printf("Standard comparison:\n"); for (int i = 0; i < 2; i++) { int res = strcoll(versions[i], versions[i+1]); printf("%s vs %s: %d\n", versions[i], versions[i+1], res); } setlocale(LC_COLLATE, "en_US.utf8"); printf("\nNumeric-aware comparison:\n"); for (int i = 0; i < 2; i++) { int res = strcoll(versions[i], versions[i+1]); printf("%s vs %s: %d\n", versions[i], versions[i+1], res); } return 0; }
此代码比较了包含数字的文件名字符串。某些区域设置支持数字感知的排序,其中 "file10.txt" 排在 "file2.txt" 之后。该示例同时显示了标准和数字感知比较结果。请注意,数字排序行为取决于区域设置的支持。为了可靠地进行数字排序,请考虑专门的比较函数。
使用 strcoll 的最佳实践
- 正确设置区域设置:在使用
strcoll
之前,请始终初始化区域设置。 - 处理空指针:在比较之前,请检查字符串是否不为 NULL。
- 考虑性能:
strcoll
可能比strcmp
慢。 - 用于面向用户的文本:在为显示目的对字符串进行排序时,首选
strcoll
。 - 在目标区域设置下进行测试:验证在所有支持的区域设置下的行为。
来源
本教程探讨了 strcoll
函数,从基本用法到特定于区域设置的行为。对于国际化应用程序,strcoll
根据文化惯例提供正确的字符串比较。在选择比较函数时,请始终考虑应用程序的具体需求。
作者
列表 C 标准库。