`
yijiangchunshui
  • 浏览: 10374 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
最近访客 更多访客>>
社区版块
存档分类
最新评论

C++宽字符串处理

    博客分类:
  • C++
阅读更多
最近两天在研究基于位运算的字符串模糊匹配时,在匹配过程中,因为中文的原因,出现了很多问题。最终发现了C++中有一个类型叫做wchar_t,宽字符,用于表示Unicode字符集,很好的解决了string和char在中文表示上的问题。以前没有引起足够的重视,现在在出现了很多问题后才不得不面对这个问题。

在我们常用的类型string和char中,对中文支持并不是很好。在这两种类型中,中文都是两个字节,也就是说中文的汉字要占用两个位置,举个简单的例子,一个“汉”字用一个char是无法表示的,即    char c = '汉' ;  是错误的,必须用 char c[3]  = "汉". 汉字占用两个字节,还有一个结尾符“0/”。string s = "汉" ; s.length()的值是2.

通过以上描述,我们会发现,我们在进行包含中文字符串处理的过程中就会遇到以下问题:在包含数字,字母,汉字的字符串处理中我们应该怎样应付各个字符占多少个字节?总不能在处理之前先转换成ASCII码判断它属于哪种字符在进行处理吧?中文取两个,字母和数字取一个。在进行判断相等与否时也遇到了问题。

1. string s = “中国人”; 想知道第二个字是不是“国”字,不能够直接使用 "s[2] == "国"",这样的s[2]是指“国”字的前一个字节代表的数字,是个负数,两个根本无法相等。必须使用 strncmp(&s[2], "国", 2);  这个函数来进行匹配。这个函数的含义是对字符串进行比较,将从第一个参数位置开始的第三个参数个字符与第二个参数进行比较,如果相等则返回0,不相等就返回1.具体到本例中s[2]开始的2个字符与“国”字进行比较。在这用情况下,不仅增加了表达的复杂度,而且增加了算法的复杂度。
2. 想进行匹配或者其他处理必须先判断类型,也就是要维护一个几乎和原字符串等长的类型链表,用于标记原字符串各个位置上的类型。在进行操作时,先判断类型,数字和字母等往后挪一位,汉字等往后挪两位,这样即麻烦又浪费存储空间。
3. 不知者在进行匹配时,用过使用 s[i] == p[j] 时会产生意想不到的结果。我就是问题出在这里。用字母进行匹配时一点问题也没有,简单的几个汉字也没有问题,但是当我使用几万字的两个文本进行匹配时就产生了很大的问题。每个汉字会被拆成两个负整数来表示,假设一个汉字被拆成了-3444,-1235,另外一个被拆成了-6433,-1235,那么本来毫无关系的两个汉字就会错误的被认为成第二个是相等的,最终的结果就会产生错误。

经过研究,发现在c++中还存在另外一个字符集体系,我之前一直没有注意到过,直到现在才明白怎么回事。

wchar_t 和 wstring的出现很好的解决了这些问题。

wchar_t c = ‘汉’; 不会出现任何问题。对应的字符串则为wstring。在这两个类型中,默认的情况下字母和数字就占用1个字节,而汉字汉用2个字节,能够很好的解决上面提到的三个问题。如:wstring s = "中国人abc" ; s.length() 的值是6,在string类型下值是9,这基本就是wstring和string的差别。

针对wstring有对应的fopen方法。对于Unicode的文件,使用下面方式读取文件,与默认的不太一样。

FILE* fp;
wchar_t utf[20000], *p = utf;
fp = _wfopen(name.c_str(), L"rb");
while(!feof(fp))
fread(p++, 1, 2, fp);
*--p = L'\0';
fclose(fp);


在宽字符指针p中就存储了文本中的内容。但是记住,一定要是Unicode的编码,如果是其他编码的文本,则会出现乱码。
string和char对应的读取字符串的方法如下:

FILE* fp = fopen(tStr.c_str(),rb);
if (fp == NULL)
{
cout<<"failed to read";
getchar();
return a;
}
fseek(fp, 0, SEEK_END);
int len = ftell(fp);
cout<<len<<endl;
rewind(fp);
char* pBuffer = new char[len+1];
memset(pBuffer, 0, len+1);
fread(pBuffer, 1, len, fp);
fclose(fp);


这样对应文本中的内容就会存在pBuffer中了。另外不能够用方法二只是稍微改动一下,即将char改为wchar_t,string改为wstring,fopen改为_wfopen,就去处理宽字符串,这样是不行的,会在正确文本的结尾产生大量乱码,估计是由于计算 len 的过程中中文按照两个长度算的,导致最后多了很多字符,成为乱码。

最后,记录一下宽字符和字符之间的转换。宽字符和字符实际上是统一的,两个之间只是所使用的字符集不同而已,以下两个函数能够比较理想的实现两者的转化:

将普通字符串转化成宽字符:

const   char   *pFilePathName   =   "c:\\aa.dll";  
int   nLen   =   strlen(pFilePathName)   +   1;  
int   nwLen   =   MultiByteToWideChar(CP_ACP,   0,   pFilePathName,   nLen,   NULL,   0);  
wchar_t   lpszFile[256];  
MultiByteToWideChar(CP_ACP,   0,   pFilePathName,   nLen,   lpszFile,   nwLen);

最终的宽字符就存储在lpszFile里

将宽字符转化成普通字符:

wchar_t utf[30], *p = utf;
char ansi[60];
p = "宽字符转化成普通字符";
WideCharToMultiByte(CP_ACP, 0, utf + 1, -1, ansi, sizeof(ansi), NULL, NULL);

最终的普通字符就存储在ansi里。
1
3
分享到:
评论

相关推荐

    VC++字符串处理函数对照表(宽字符与ANSI字符)

    本文档列出了标准C语言ANSI字符与C++宽字符的处理函数对照表,对于处理宽字符是很好的参考文件。

    C++字符串完全指引

    本文摘自VC知识库 原著:Michael Dunn 翻译:Chengjie Sun 对C++字符串非常详尽的解释,我看完后对以前比较模糊的多字符集、宽字节等概念有种豁然开朗的感觉。特地分享给大家。

    VC++对字符串处理

    精心整理,大家在使用VC++处理字符串的时候肯定遇到unicode 宽字符的问题: 比如:“不能将参数 1 从“const char [5]”转换为“LPCTSTR””之类的问题。 在此文档中告诉你怎么转换。 cstring 转换 char cstring ...

    C++编程思想(第2版 第2卷)

    介绍C++的字符串、输入输出流、STL算法、容器和模板的现代用法,包括模板元编程;解释多重继承问题的难点,展示RTTI的实际使用,描述了典型的设计模式及其实现,特别介绍被认为是标准C++下一版特征之一的多线程处理...

    C/C++头文件一览

    #include &lt;string.h&gt; //字符串处理 #include &lt;strstrea.h&gt; //基于数组的输入/输出 #include &lt;time.h&gt; //定义关于时间的函数 #include &lt;wchar.h&gt; //宽字符处理及输入/输出 #include &lt;wctype.h&gt; //宽字符分类

    本人精心收集,c++头文件一览

     //字符串处理 #include &lt;strstrea.h&gt; //基于数组的输入/输出 #include &lt;time.h&gt; //定义关于时间的函数 #include &lt;wchar.h&gt; //宽字符处理及输入/输出 #include &lt;wctype.h&gt; //宽字符...

    C和C++头文件对比一览

    #include &lt;string.h&gt; //字符串处理 #include &lt;strstrea.h&gt; //基于数组的输入/输出 #include &lt;time.h&gt; //定义关于时间的函数 #include &lt;wchar.h&gt; //宽字符处理及输入/输出 #include &lt;wctype.h&gt; //宽字符分类 ...

    C/C++头文件大全

     字符串处理 #include &lt;strstrea h&gt; 基于数组的输入/输出 #include &lt;time h&gt; 定义关于时间的函数 #include &lt;wchar h&gt; 宽字符处理及输入/输出 #include &lt;wctype h&gt; 宽字符分类 int ...

    C++大学教程,一本适合初学者的入门教材(part2)

    5.12.2 字符串处理库的字符串操作函数 5.13 有关对象的思考:对象间的交互 小结 术语 自测练习 自测练习答案 练习 特殊小节:建立自己的计算机 更多的指针练习 字符串操作练习 特殊小节:高级字符串操作练习 复杂...

    C++大学教程,一本适合初学者的入门教材(part1)

    5.12.2 字符串处理库的字符串操作函数 5.13 有关对象的思考:对象间的交互 小结 术语 自测练习 自测练习答案 练习 特殊小节:建立自己的计算机 更多的指针练习 字符串操作练习 特殊小节:高级字符串操作练习 复杂...

    -C++参考大全(第四版) (2010 年度畅销榜

    31.4 宽字符串转换函数 31.5 宽字符数组函数 31.6 多字节/宽字符转换函数 第四部分 标准C++类库 第32章 标准C++I/O类 32.1 I/O类 32.2 I/O头文件 32.3 格式化标记和I/O操作算子 32.4 几个数据类型 32.5 重载运算符...

    新手学习C++入门资料

    标准C++中的字符串类取代了C标准C函数库头文件中的字符数组处理函数。 C++中用来做控制态输入输出的iostream类库替代了标准C中的stdio函数库。 C++中的try/catch/throw异常处理机制取代了标准C中的setjmp()和...

    C++MFC教程

    CStringArray:用来表示可变长度的字符串数组。数组中每一个元素为CString对象的实例。下面介绍几个成员函数: Add 增加CString RemoveAt 删除指定位置CString对象 RemoveAll 删除数组中所有CString对象 GetAt ...

    VC++6.0核心编程源码.rar

    当然,你首先必须自己转换字符串,然后将已转换的消息表资源嵌入你的.exe文件或DLL模块,不过,这时该函数会选定正确的嵌入对象。ErrorShow示例应用程序(本章后面将加以介绍)展示了如何调用该函数,以便将...

    c语言库函数使用大全及头文件介绍

    #include &lt;string.h&gt; //字符串处理 #include &lt;strstrea.h&gt; //基于数组的输入/输出 #include &lt;time.h&gt; //定义关于时间的函数 #include &lt;wchar.h&gt; //宽字符处理及输入/输出 #include &lt;wctype.h&gt; //宽字符分类 ...

    基于C++开发的射击游戏

    // 读取完后m_sEnimyName中的字符串是每个section name的连接,两两之间用”\0”字符分开,如: // “enimy01.enimy02.enimy03”其中的点就是空字符 GetPrivateProfileSectionNames(m_sEnimyName, sizeof(m_...

    Visual C++ 编程资源大全(源码 文件)

    文件名包含全路径名(10KB)&lt;END&gt;&lt;br&gt;12,profile.zip 操作ini文件的例子(5KB) 13,scanfile.zip 如何在一个长文件中查找某一个特定的字符串(2KB)&lt;END&gt;&lt;br&gt;14,iniedit.zip 如何编辑ini文件以及任何包含文本...

Global site tag (gtag.js) - Google Analytics