0)printf("okay\n");//匹配成功elseprintf("none\n");/" />
[C++]string中文的匹配问题 您所在的位置:网站首页 电脑装机大师查询匹配出错 [C++]string中文的匹配问题

[C++]string中文的匹配问题

2024-05-31 14:15| 来源: 网络整理| 查看: 265

*何谓匹配*

根据string定义的find函数,可以实现查找子串:

string str("abc"); if ((int)str.find("bc") > 0) printf("okay\n"); // 匹配成功 else printf("none\n"); // 匹配失败 // 输出 okay

[注] 使用printf的原因是库编译速度更快一些。

运行,使用大量数据,程序运行状况良好。

然而,如果使用其处理中文,会发现:

string str("人类"); if ((int)str.find("死") > 0) printf("okay\n"); // 匹配成功 else printf("none\n"); // 匹配失败 // 输出 okay

竟然匹配了!?

*探求原因*

为什么会产生这种输出呢? 我们来想一下string.find是怎样查找的。 按字符查找! 那么,“人类”有几个字符(’\0’排外)呢?

printf("%d\n",string("人类").length()); // 4

咦?奇怪,分明是2个,怎么有4个呢?

原来,Windows中1,中文(简体)通常使用GBK来编码的。

我们来看看“人类”是怎么编码的:

printf("%X ", "人类"[0]); printf("%X ", "人类"[1]); printf("%X ", "人类"[2]); printf("%X ", "人类"[3]); // FFFFFFC8 FFFFFFCB FFFFFFC0 FFFFFFE0

请看! “人类”的GBK编码是C8CB C0E0。

printf("%X ", "死"[0]); printf("%X ", "死"[1]); // FFFFFFCB FFFFFFC0

而“死”的编码是CBC0! 这样一来,使用string的find函数进行搜索时,”人类”能够匹配”死”的问题就瞬间搞懂了。

*问题求解*

那么,怎么解决呢?

经查询资料: GBK分两段:ASCII段和中文段。ASCII段使用单字节,和ASCII编码保持一致;中文(及特殊符号)段使用双字节编码。在双字节段中,第一字节的范围是81–FE(也就是不含80和FF),第二字节的一部分领域在40–7E,其他领域在80–FE2。 也就是说,在GBK编码中,中文有两个字节,首字节范围81~FE,尾字节范围40~7E。 这么说来,判断一个字符(或者中文的一个字)是否为中文,只要判断其是否大于0x80即可。在判断其大于时,获取两个字节,同时向下跳一字节,进行后续判断;如果不大于,则为ASCII字符,获取一个字节。

根据以上所述,我们利用union将字符化为int型。

代码如下:

std::vector stringToVecInt(const std::string &str) { union { char c[2]; int i; } convert; // 段位清零 convert.i = 0; std::vector vec; for (unsigned i = 0; i < str.length(); i++) { // GBK编码首字符大于0x80 if ((unsigned)str[i] > 0x80) { // 利用union进行转化,注意是大端序 convert.c[1] = str[i]; convert.c[0] = str[i + 1]; vec.push_back(convert.i); i++; } else // 小于0x80,为ASCII编码,一个字节 vec.push_back(str[i]); } return vec; }

我们使用里的search函数,进行子串的搜索。

bool include(const std::string &str, const std::string &msg) { auto sour = stringToVecInt(str); auto find = stringToVecInt(msg); return std::search(sour.begin(), sour.end(), find.begin(), find.end()) != sour.end(); }

测试下效果:

if (include("人类","死")) printf("okay\n"); // 匹配成功 else printf("none\n"); // 匹配失败 // none

成功!

*后续思考*

其实,GBK的编码可以直接写在字符串里: 比如”人类”就是”\xC8\xCB\xC0\xE0”。

编码问题,是相当复杂的问题,凡是有字符串处理,多少都会遇到编码的问题。 本文问题的提出和解决是基于GBK编码的,而在互联网中,UTF-8、Unicode等编码也是经常使用的。在处理字符串时,一定要留心各种可能发生的编码问题,毕竟问题是永远解决不完的。

2016.1.30

笔者使用Windows下的Visual Studio 2015作为开发环境。 ↩详见维基百科:汉字内码扩展规范 ↩


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有