不同区域设置(C与en_US.utf8)下C++字符串比较异常问题
问题描述
在使用en_US.utf8区域设置进行C++字符串比较时,发现如下异常行为:
- 单独比较字符串"A"与"a":
C区域设置(默认)返回A < a,而en_US.utf8区域设置返回A > a; - 比较字符串"A0"与"ad":两个区域设置均返回
A0 < ad。
按直觉的比较逻辑应先对比首字符"A"与"a",但en_US.utf8下组合字符串的比较结果与单个字符的比较结果矛盾。验证代码如下:
#include <iostream> #include <string> void cmp_strs(std::locale l, std::string s1, std::string s2) { auto &f = std::use_facet<std::collate<char>>(l); std::cout << l.name() << ": "; std::cout << f.compare(&s1[0], &s1[0] + s1.size(), &s2[0], &s2[0] + s2.size()) << ' '; std::cout << "\n"; } int main() { std::cout << "A v a\n"; std::string a = "A"; std::string b = "a"; cmp_strs(std::locale("C"), a, b); cmp_strs(std::locale("en_US.utf8"), a, b); std::cout << '\n'; std::cout << "A0 v ad\n"; a = "A0"; b = "ad"; cmp_strs(std::locale("C"), a, b); cmp_strs(std::locale("en_US.utf8"), a, b); }
请问为何会出现这种首字符比较结果与组合字符串比较结果不一致的情况?
原因分析
这是因为en_US.utf8区域设置采用Unicode多级权重排序规则,和C区域设置的逐字符ASCII值比较逻辑完全不同:
单个字符"A"与"a"的比较:
在Unicode排序规则中,大小写字母的主权重一致(字典序默认忽略大小写),当两个字符仅存在大小写差异时,会触发次权重比较。如果系统中en_US.utf8的次权重规则将大写字母权重设为高于小写字母,就会出现"A" > "a"的结果。组合字符串"A0"与"ad"的比较:
比较时首先对比首字符的主权重——"A"和"a"的主权重相同,此时直接进入第二个字符的主权重比较:数字"0"的主权重远低于字母"d"的主权重(Unicode排序规则中数字排在字母之前),因此整个字符串"A0"被判定为小于"ad",不会触发大小写的次权重比较。
核心逻辑是:组合字符串比较时,首字符主权重相同后会直接比较后续字符,不会纠结于大小写的次权重;只有当所有字符的主权重都一致时,才会用次权重区分大小写。
内容的提问来源于stack exchange,提问作者ксения петренко
相关产品推荐
相关产品推荐

