ICU排序:如何按数字顺序比较含前导零的数字字符串?
解决方案
ICU 的UCOL_NUMERIC_COLLATION属性是基于数值大小做比较的,它会直接忽略前导零,所以001和01会被解析为同一个数值1,自然返回相等结果,这和你的需求不匹配。要实现带前导零的特殊排序规则,必须自定义比较逻辑,不能单纯依赖ICU的内置数字排序特性。
自定义比较逻辑步骤
- 第一步:把两个字符串转成数值(推荐用
uint64_t避免溢出),先比数值大小:- 若
s1数值 <s2数值,返回-1; - 若
s1数值 >s2数值,返回1;
- 若
- 第二步:如果数值相等,再比字符串的长度:
- 若
s1长度 >s2长度,返回-1(比如001长度3,01长度2,所以001 < 01); - 若
s1长度 <s2长度,返回1;
- 若
- 第三步:如果数值和长度都相等,最后按字符串字典序比较(此时两个串本质完全相同,返回0)。
代码实现示例
#include <stdint.h> #include <string.h> #include <stdlib.h> int customNumericCompare(const char *s1, const char *s2) { // 转换为无符号长整型,假设输入都是正整数,带负数需调整逻辑 uint64_t num1 = strtoull(s1, NULL, 10); uint64_t num2 = strtoull(s2, NULL, 10); if (num1 != num2) { return num1 < num2 ? -1 : 1; } // 数值相同,比较字符串长度 size_t len1 = strlen(s1); size_t len2 = strlen(s2); if (len1 != len2) { return len1 > len2 ? -1 : 1; } // 数值和长度都相同,按字典序收尾 return strcmp(s1, s2); }
结合排序函数使用
如果需要对字符串数组排序,直接用qsort配合上面的自定义比较函数即可:
// 示例排序数组 char *numStrings[] = {"01", "001", "002", "0011"}; size_t count = sizeof(numStrings) / sizeof(numStrings[0]); qsort(numStrings, count, sizeof(char*), (int (*)(const void*, const void*))customNumericCompare); // 排序后结果:001, 01, 002, 0011
这个逻辑完全符合你要求的排序规则,既保证了数值顺序,又通过长度区分了前导零不同的同数值字符串。
内容的提问来源于stack exchange,提问作者Y FY
相关产品推荐
相关产品推荐

