最近遇到一个问题,需要判断一个字符串中是否包含汉字、拼音、普通字符,于是就简单记录下来。

首先,如何判断这些,绕不开操作系统中的编码,常见的有三种:ASCII、Unicode、UTF-8

ASCII

这是最早的一种编码方式,因此只将英文字符编码进去了,也就是一些大小写字母和一些符号。但是,由于后续计算机扩展到各个国家,各国的语音也需要编码,因此ASCII编码(00000000 - 01111111)127位就不够用了,于是就制定了其他编码方式。
各国都有各自的一套编码方式,比如中国制定了GB2312编码,日本把日文编入了Shift_JIS里等等,这样造成的结果就是会发生冲突,因此,Unicode应运而生。

Unicode

Unicode把所有符号都统一到一套编码里,这样就不会再有乱码问题了(Unicode 兼容了ASCII码)。 Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持Unicode。

ASCII和Unicode的区别

ASCII编码是1个字节,而Unicode编码通常是2个字节,举例如下。

  • 字母 A 用ASCII编码是十进制的65,二进制的01000001;

  • 字符 0 用ASCII编码是十进制的48,二进制的00110000,注意字符 ‘0’ 和整数 0 是不同的;

  • 汉字 中 已经超出了ASCII编码的范围,用Unicode编码是十进制的20013,二进制的01001110 00101101。

  • 如果把ASCII编码的 A 用Unicode编码,只需要在前面补0就可以,因此, A 的Unicode编码是00000000 01000001。

UTF-8

考虑到一个问题:如果文件里都是由英文字符组成,如果由Unicode编码,那么会浪费整整一倍的空间(因为英文是由ASCII码表示,所以前八位都是0)。又出现了把Unicode编码转化为“可变长编码”的UTF-8编码,UTF-8编码把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字一般编为3个字节。

字符 ASCII Unicode UTF-8
A 01000001 00000000 01000001 01000001
- 01001110 00101101 11100100 10111000 10101101

从上面的表格可以发现UTF-8编码一个额外的好处,就是ASCII编码实际上可以被看成是UTF-8编码的一部分,所以,大量只支持ASCII编码的历史遗留软件可以在UTF-8编码下继续工作。

强调一下,unicode是一种编码方式,和ascii是同一个概念,而UTF-8,UTF-16等是一种存储方式,在存储和传输上节约空间、提高性能的一种编码形式。

计算机内部使用通用编码方式

在C++的std::string中使用的是UTF-8格式,可以通过下面代码验证:

#include <iostream>
using namespace std;
int main(){string s = "你好啊abb";cout << s.size() << endl;for(int i=0; i<s.size(); i++){cout << "s[" << i << "] = "  << s[i] << " ,s[" << i << "].size() = " << sizeof(s[i]) << endl;printf("0x%02x ", (unsigned char)s[i]);cout << endl;}
}

结果:

首先,字符串s的size是12,一个中文3个字节,所以总共是12个字节。另外,cout默认会用ASCII码打印出字符,所以前面9个字节打印出来是乱码,不过我们可以打印出对应的十六进制编码,如结果中所示,汉字“中”打印出来的结果就是 0xe4bda0,我们可以利用一些网站来查询字符对应的编码,比如
查看字符UTF-8编码
查询字符Unicode编码
UFT-8 编码对照表
可以查到,汉字“中”对应的UTF-8编码就是0xE4BDA0

那么,现在有了一个问题:当我们拿到内存中的 UTF-8 数据,该怎么去读取?是分一个字节读取,还是两个字节,三个字节?

如何对 UTF-8 数据进行decode

还是回到ASCII码,ASCII码由一个字节表示,一个字节最多可表示256个符号,但是,ASCII中只包含128个符号,也就是00000000 - 011111111,所以可以通过字符的首位进行判断(个人猜测,当初设计的时候,应该也是考虑到了识别问题,所以将首位设为0,只表示128种符号)。事实上计算机确实是按这个来进行识别的:

UTF-8 规定:

  1. 单字节的字符,字节的第一位设为0,对于英语文本,UTF-8码只占用一个字节,和ASCII码完全相同;
  2. n个字节的字符(n>1),第一个字节的前n位设为1,第n+1位设为0,后面字节的前两位都设为10,这n个字节的其余空位填充该字符unicode码,高位用0补足。

这样就形成了如下的UTF-8标记位:
0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

中文一般都是三个字节表示,即上面第三行的格式。

其他字符集 GB2312、GBK等

为什么在unicode和UTF-8大行其道的同时,GB2312和GBK仍在广泛使用 ?

  • 原因就在于UTF-8表示中文的时候,需要3个字节,如果是全中文的文件,这样对于双字节的编码方法,会多浪费50%的额外空间。所以,GB2312和GBK仍在广泛使用

日常随笔——如何判断字符是汉字、字母、还是拼音? 在C++中又该如何判断?相关推荐

  1. Python中判断字符是否为字母、数字、字母和数字组合,验证回文串(LeetCode125)

    判断字符串是否为字母.数字 函数str.isdigit()判断字符是否为数字,函数str.isalpha()判断字符是否为字母,函数isalnum()判断字符是否为数字字母组合. 上代码: str1 ...

  2. 判断字符是否为字母或者数字

    判断是否为大小写字母 返回的是int型 int tolower(int c) {if ((c >= 'A') && (c <= 'Z'))return c + ('a' - ...

  3. java 判断是否字母_java判断字符是否为字母的方法

    java判断字符是否为字母的方法 发布时间:2020-06-29 18:01:37 来源:亿速云 阅读:239 作者:Leah 这篇文章运用简单易懂的例子给大家介绍java判断字符是否为字母的方法,代 ...

  4. java如何判断字符是否是字母?

    关于java判断字符的文章早已是非常多了,本文是对我个人过往学习java,理解及应用java的一个总结.此文内容涉及java如何判断字符是否是字母的基本方法,希望对大家有所帮助. java如何判断字符 ...

  5. c语言判断字符是否为某字母,判断字符是否为字母

    问题一:java 判断一个字符是否为字母int start,end,i=0; char[] ch = s.toCharArray(); while(!Character.isLetter(ch[i]) ...

  6. python判断是不是字母_python判断字符是否为字母和数字

    在使用python语言中的字符串方法时,可以使用它们判断字符串中是否有字母或数字或其他的构成.下面利用几个实例说明字符串方法的用法,操作如下:python学习网,大量的免费python视频教程,欢迎在 ...

  7. python判断字符是英文字母怎么回事_python判断字符串是否包含字母

    第一种方法:使用正则表达式判断字符串是否包含字母#-*- coding:utf-8 -*-import re def check(str): my_re = re.compile(r'[A-Za-z] ...

  8. python判断字符是否是数字和字母_python判断字符是否为字母和数字

    在使用python语言中的字符串方法时,可以使用它们判断字符串中是否有字母或数字或其他的构成.下面利用几个实例说明字符串方法的用法,操作如下:云海天教程网,大量的免费python教程,欢迎在线学习!s ...

  9. python怎么识别字母数字的_python判断字符是否为字母和数字

    在使用python语言中的字符串方法时,可以使用它们判断字符串中是否有字母或数字或其他的构成.下面利用几个实例说明字符串方法的用法,操作如下: str_1 = "123" str_ ...

  10. 判断字符是否为字母c语言,C程序检查字符是否为字母

    C程序检查字符是否为字母 在此示例中,您将学习检查用户输入的字符是否为字母. 要理解此示例,您应该了解以下C语言编程主题: 在C语言编程中,字符变量保存的是ASCII值(0到127之间的整数),而不是 ...

最新文章

  1. Linux System Programming --Chapter Five
  2. [J2ME] Signing a midlet suite的讨论稿[Update]
  3. Oracle常用的几个父栓
  4. 机器学习之 sklearn.preprocessing 模块
  5. linux怎么运行g77,Linux安装g77编译器的技巧
  6. 作者:石勇(1956-),男,中国科学院大学经济管理学院教授、博士生导师
  7. SpringCloud Consul注册中心介绍及配置使用
  8. nginx 根据目录指定root_CentOS(7.6)基本操作与Nginx配置
  9. [转]OpenGL基础技术讲座--发展历史
  10. mysql 主从的几个参数
  11. 计算机网络的创新创业计划书,互联网创新创业计划书.doc
  12. 百度翻译api和SpringBoot集成
  13. 开源电子书项目FBReader初探(五)
  14. github国内镜像站
  15. java 后台管理模板_后台管理系统模板 - WEB源码|JSP源码/Java|源代码 - 源码中国
  16. 《Python编程:从入门到实践》配套资源 官方网站免费下载
  17. 为什么一个数的平方,会变负数?结果令人惊讶(sq代码解析)
  18. 第一章:快乐的老青蛙
  19. 大学matlab选择试题和答案,Matlab与信息处理-中国大学mooc-试题题目及答案
  20. 读《活在网络里 大升级时代的人类新进化》

热门文章

  1. 赶紧换掉windows系统自带记事本
  2. 河北师范大学汇华学院计算机类,河北师范大学汇华学院
  3. 2022年泰迪杯数据分析_B题:银行客户忠诚度分析赛题数据_任务五
  4. [阿里DIN] 从论文源码学习 之 embedding层如何自动更新
  5. 从甲骨文中国研发中心大裁员细说技术人员的未来
  6. 新概念英语(1-99)Ow!
  7. 初遇Flarum_搭建安装的遇坑填坑过程
  8. 事件10016,RuntimeBroker无法编辑
  9. 一文彻底理解I/O多路复用
  10. 论文阅读 Performance Comparison Between Linux Containers and Virtual Machines