Hanqing Back-end Dev Engineer

如何判断字符串中含有中文字符


最近在项目中遇到一个问题,上游接口返回的图片地址uri中含有中文,导致客户端无法显示图片。这种含有中文的图片uri是非法的,需要过滤掉,那么问题就归结到如何判断一个字符串中国含有中文。这实际是考察你对字符编码的理解。首先我们了解下unicode及utf-8编码。

unicode本质上是一个字符集,或者说是一个字符编码的规范,它可以给地球上每一个字符一个唯一的编码方式。针对unicode,有utf-8/utf-16/utf-32等的实现方式,他们或者是变长或者是定长的编码方式,比如utf-32就是定长的编码,再比如utf-8就是变长的编码。因此,理论上来讲unicode可以表示上亿个不同的字符串。

针对utf-8的实现来讲,它使用1-4个字节来表示一个符号,根据不同的符号变换不同的长度。具体规则有两条,

  1. 针对单字节的符号,字节第一位为0,后面7位是unicode编码,对于英文字符,utf-8编码就是ASCII编码,ASCII的编码范围是0x00到0x7f。
  2. 针对n字节的符号(n>1),第一个字节的前n为都是1,第n+1位是0,后面所有字节的前两位都是10,剩下的的bit位就是这个符号的utf-8编码。

总结一下编码规则如下,

unicode符号范围(十六进制) |     utf-8编码方式(二进制)
---------------------------------------------------------
0000 0000 - 0000 007F     |     0xxxxxxx
0000 0080 - 0000 07FF     |     110xxxxx 10xxxxxx
0000 0800 - 0000 FFFF     |     1110xxxx 10xxxxxx 10xxxxxx
0001 0000 - 0010 FFFF     |     11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

我们以汉字“严”为例,演示如何由unicode实现utf-8编码, 严的unicode表示为4E25,二进制表示为100111000100101,符合上图中的第三种情况,初步判断二进制表示为1110xxxx 10xxxxxx 10xxxxxx,我们就从“严”的二进制最后一位开始依次向前填入,可以得到“严”的utf-8表示,11100100 10111000 10100101,转换为十六进制就是E4B8A5。

中文在unicode中的表示范围为为4E00-9FA5,那么判断字符串中是否含有中文可以使用正则匹配,就有第一种实现方式

$str = '北京';
if(preg_match('/[\x{4e00}-\x{9fa5}]/u', $str)){
    echo 1;
}else{
    echo 0;
}

汉字中不可能出现英文的ASCII编码,ASCII的编码范围是0x00-0x7F,共128个字符,那么除过英文字符就是中文字符,就有第二种实现方式

if(preg_match("/[\x7f-\xff]/", $str)){
    echo 1;
}

只要其中含有非ASCII字符的,就包含非英文字符。


Comments

Content