linux c/c++ 判断是否为中文(不包括中文符号,非正则)

在linux环境下,c/c++默认的中文编码为UTF-8,中文的unicode编码是双字节的编码。有趣的是,windows环境下中文utf-8的编码为两个字节,而linux环境下UTF-8的为三个字节,而匹配中文使用正则表达式为

 

[\u4e00-\u9fa5]


无论你是怎么搜索,百度出来匹配中文的正则基本都是上述的表达式。因此linux环境下3字节的UTF-8也用这个正则来匹配显然是不正确的。

 

Linux环境下的正则匹配规则中

 

\un,其中的 n 是一个用四个十六进制数字表示的 Unicode字符。并不支持三个字节的utf-8

 

\xn,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如, '\x41'匹配 "A"。'\x041' 则等价于 '\x04' & "1"。正则表达式中可以使用 ASCII编码。

因此得考虑将三个字节转变成2个字节,再进行中文的匹配。

先看双字节的unicode是如何转化成三字节的utf-8

 

   |  Unicode符号范围      |  UTF-8编码方式
 n |  (十六进制)           | (二进制)
---+-----------------------+------------------------------------------------------
 1 | 0000 0000 - 0000 007F |                                              0xxxxxxx
 2 | 0000 0080 - 0000 07FF |                                     110xxxxx 10xxxxxx
 3 | 0000 0800 - 0000 FFFF |                            1110xxxx 10xxxxxx 10xxxxxx
 4 | 0001 0000 - 0010 FFFF |                   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
 5 | 0020 0000 - 03FF FFFF |          111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
 6 | 0400 0000 - 7FFF FFFF | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

 

查表可知,

\u4e00-\u9fa5

 

处于n=3的编码处,例如4E00,那么将它先转化成16进制(不足16位的在前面补0)

 

0000 1110 0000 0000

根据第三行的格式,也就是将上述16个比特位重新断句

 

 

0000 111000 000000

从左至右分别放置到以下的xx处

 

 

1110xxxx 10xxxxxx 10xxxxxx

得到三字节的UTF-8编码

 

 

11100000 10111000 10000000

也就是0xE0 B8 80

 

经计算可知,无法只用一个范围来确定三字节的中文要怎么表示,所以还是将其转化成双字节来匹配中文。

将上述推理反推,就能知道三字节的UTF-8如何转变成双字节的unicode编码。既然知道原理,就没有必要再用正则来判断字符是否为中文了。

#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
bool is_chinese(const string& str)
{
  unsigned char utf[4] = {0};
  unsigned char unicode[3] = {0};
  bool res = false;
  for (int i = 0; i < str.length(); i++) {
    if ((str[i] & 0x80) == 0) {
      res = false;
    }
    else{
      utf[0] = str[i];
      utf[1] = str[i + 1];
      utf[2] = str[i + 2];
      i++;
      i++;
      unicode[0] = ((utf[0] & 0x0F) << 4) | ((utf[1] & 0x3C) >>2);
      unicode[1] = ((utf[1] & 0x03) << 6) | (utf[2] & 0x3F);

      if(unicode[0] >= 0x4e && unicode[0] <= 0x9f){
         if (unicode[0] == 0x9f && unicode[1] > 0xa5)
                res = false;
         else         
               res = true;
      }else
         res = false;
    }
  }
  return res;
}
 
int main(){
        string str="中国";
        string str1="asdasfdsfd";
        string str2="中国";
        cout << is_chinese(str) <<endl;
        cout << is_chinese(str1) <<endl;
        cout << is_chinese(str2) <<endl;
        return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值