xiaoxi666 Master programmers think of systems as stories to be told rather than programs to be written. 博客园 首页 新随笔 联系 订阅 管理 你写的字符(串)忽略大小写比较函数真的严谨吗?

提示 阅读本文需要同时对c++和java有一定了解。 背景 有时我们比较两个字符串时不考虑它们是大写还是小写;举个例子,在这种情况下我们认为“BanAna”和“baNaNA”是等价的。 其中一种思路是: 1. 将两个字符串都转换为小写(或者都转换为大写); 2.比较转换后的两个字符串是否相同。 这里给出一段C++示例代码: 复制代码 //C++ example that we offen use bool testIgnoreCase(string str1, string str2){ transform(str1.begin(),str1.end(),str1.begin(),::tolower); transform(str2.begin(),str2.end(),str2.begin(),::tolower); //Or //transform(str1.begin(),str1.end(),str1.begin(),::toupper); //transform(str2.begin(),str2.end(),str2.begin(),::toupper); cout<>>1. if ((ooffset < 0) || (toffset < 0) || (toffset > (long)value.length - len) || (ooffset > (long)other.value.length - len)) { return false; } while (len-- > 0) { char c1 = ta[to++]; char c2 = pa[po++]; if (c1 == c2) { continue; } if (ignoreCase) { // If characters don't match but case may be ignored, // try converting both characters to uppercase. // If the results match, then the comparison scan should // continue. char u1 = Character.toUpperCase(c1); char u2 = Character.toUpperCase(c2); if (u1 == u2) { continue; } // Unfortunately, conversion to uppercase does not work properly // for the Georgian alphabet, which has strange rules about case // conversion. So we need to make one last check before // exiting. if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) { continue; } } return false; } return true; } 复制代码 可以看到,Java中的忽略大小写比较先将字符转换为大写,对于不相等的字符,又转换为小写比较;这样做相当于多了一层保障。 再细究,我们先看小写转换,观察其更为底层的实现: 复制代码 1 int toLowerCase(int ch) { 2 int mapChar = ch; 3 int val = getProperties(ch); 4 5 if ((val & 0x00020000) != 0) { 6 if ((val & 0x07FC0000) == 0x07FC0000) { 7 switch(ch) { 8 // map the offset overflow chars 9 case 0x0130 : mapChar = 0x0069; break; 10 case 0x2126 : mapChar = 0x03C9; break; 11 case 0x212A : mapChar = 0x006B; break; 12 case 0x212B : mapChar = 0x00E5; break; 13 // map the titlecase chars with both a 1:M uppercase map 14 // and a lowercase map 15 case 0x1F88 : mapChar = 0x1F80; break; 16 /*******为保证阅读效果,省略很多case*******/ 17 case 0xA7AA : mapChar = 0x0266; break; 18 // default mapChar is already set, so no 19 // need to redo it here. 20 // default : mapChar = ch; 21 } 22 } 23 else { 24 int offset = val << 5 >> (5+18); 25 mapChar = ch + offset; 26 } 27 } 28 return mapChar; 29 } 复制代码 源码中的getProperties,获取到字符的属性(感兴趣的可以阅读源码),然后根据不同的情况执行对应的操作。对于我们的例子,第9行 复制代码 case 0x0130 : mapChar = 0x0069; break; 复制代码 将İ(304)转换为i(105)。注意程序中是16进制的。 再看大写转换: 复制代码 1 int toUpperCase(int ch) { 2 int mapChar = ch; 3 int val = getProperties(ch); 4 5 if ((val & 0x00010000) != 0) { 6 if ((val & 0x07FC0000) == 0x07FC0000) { 7 switch(ch) { 8 // map chars with overflow offsets 9 case 0x00B5 : mapChar = 0x039C; break; 10 case 0x017F : mapChar = 0x0053; break; 11 case 0x1FBE : mapChar = 0x0399; break; 12 // map char that have both a 1:1 and 1:M map 13 case 0x1F80 : mapChar = 0x1F88; break; 14 /*******为保证阅读效果,这里省略很多case*******/ 15 case 0x2D2D : mapChar = 0x10CD; break; 16 // ch must have a 1:M case mapping, but we 17 // can't handle it here. Return ch. 18 // since mapChar is already set, no need 19 // to redo it here. 20 //default : mapChar = ch; 21 } 22 } 23 else { 24 int offset = val << 5 >> (5+18); 25 mapChar = ch - offset; 26 } 27 } 28 return mapChar; 29 } 复制代码 转换ı(305)时,程序跳到了第24行: 复制代码 int offset = val << 5 >> (5+18); 复制代码 将其转换为I(73)。 至此,上面的例子可以正常运行了。 总结 对于Java: 1. 对于Ascii码表中的字符,传统方法(只转换为大写或小写)完全没有问题; 2. 若要考虑更多字符集,需多加考虑,这时要多加一次转换和比较。除了文中列举的字符,还有其他字符存在类似的问题。 对于C++: 1. 对于Ascii码表中的字符,传统方法(只转换为大写或小写)完全没有问题; 2. C++对于超出Ascii码表的字符处理方式和Java不同。由于看不到tolower的源码,这里没有进一步分析,有知晓的读者欢迎留言。 后记 1. 文中涉及到了“等价”和“相等”的概念,这里不做具体区分,可参考《Effective C++》详细了解。 2. C++还有其他函数如strcasecmp/stricmp可以忽略大小写比较,它们都是只转换为小写后比较,具体可以看官网说明: XXX compares string1 and string2 without sensitivity to case. All alphabetic characters in the two arguments string1 and string2 are converted to lowercase before the comparison. 参考话题 https://stackoverflow.com/questions/15518731/understanding-logic-in-caseinsensitivecomparator 好用的工具网站 字符码在线查询 https://www.litefeel.com/tools/ascii.php 『注:本文来自博客园“小溪的博客”,若非声明均为原创内容,请勿用于商业用途,转载请注明出处http://www.cnblogs.com/xiaoxi666/』 分类: c++,javahttps://www.cnblogs.com/xiaoxi666/p/9535084.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信