多字节字符集字符串的遍历问题

    写程序经常与文件打交道,常常会需要将文件名从一个完整的路径中分离出来,分离的方法很简单,就是寻找路径字符串中最后一个'//'的位置,后面的便是文件名的开始位置,于是会有这样的代码:
  1. std::string fullPath = ...
  2. std::string::size_type pos = fullPath.find_last_of('//');
  3. ...
这段代码在99%情况下都不会出错,但是在面对这样的路径时就会出问题:
C:/Program File/XXX
其中XXX是汉字,而且其中的某个汉字的第二个字节的值为0x5C。这是为什么呢?

首先从多字节字符集说起,多字节字符集的字符串的每个单位还是 char,但是字符串中可能包括单字节的ASCII编码字符与双字节的东方字符(如汉字)区分的方法是双字节符的第一个字节叫LeadByte,第二个叫TraitByte,LeadByte的编码范围大于0x7F(这个值可能不准确,至少LeadByte的值大于ASCII编码值的最大值)TraitByte则没有限制,在遍历时,如果发现一个字节的值大于0x7F,则表示这是双字节字符的首字节,后面为TraitByte。

而std::string是STL中basic_string对char的特化版本类,故它只适合存多字节字符集。其find_last_of在实现时(Windows),是从最后开始逐个遍历,直到找到与传入的字符匹配为止。
所以当一个汉字的TraitByte值正好等于要找的ASCII字符的编码值时,find_last_of就会返回这个TraitByte的位置,显然这是不正确的。

那么该怎么做呢,Windows上提供了一套函数,比如,要寻找多字节字符串中指定字符位置的前一个字符位置,使用:

LPCTSTR
 CharPrev(  LPCTSTR  lpStart,,  LPCTSTR  lpCurrent)

其中lpStart指向字符串的起始位置,lpCurrent指向指定字符的位置,返回lpCurrent所指的字符的前个字符的位置。
可以想象其多字节版的实作:
  1. LPCTSTR CharPrev( LPCTSTR lpStart,, LPCTSTR lpCurrent)
  2. {
  3.     if (lpCurrent > lpStart + 1) {
  4.         if (*(lpCurrent - 2) > 0x7F)
  5.             return lpCurrent - 2;
  6.         return lpCurrent - 1;
  7.     }
  8.     else if ...
  9. }
用它来完成数量并不大的遍历,性能并不会下降太多。
其实CharPrev只是个宏,它分为CHarPrevA 与 CharPrevW 版,分别对应多字节与Unicode字符集。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值