字符编码与使用中的问题

简介: 作为中文环境下开发的Java程序员,UTF-8编码是我们经常使用的编码方式。字符编码是怎么来的?为什么使用UTF-8编码?使用字符编码的时候回遇到什么坑?这些问题你遇到过或者思考过吗。

作为中文环境下开发的Java程序员,UTF-8编码是我们经常使用的编码方式。

字符编码是怎么来的?为什么使用UTF-8编码?使用字符编码的时候回遇到什么坑?

这些问题你遇到过或者思考过吗。

字符编码表

在显示器上看见的文字、图片等信息在电脑里面其实并不是我们看见的样子,即使你知道所有信息都存储在硬盘里,把它拆开也看不见里面有任何东西,只有些盘片。

假设,你用显微镜把盘片放大,会看见盘片表面凹凸不平,凸起的地方被磁化,凹的地方是没有被磁化;凸起的地方代表数字1,凹的地方代表数字0。硬盘只能用0和1来表示所有文字、图片等信息。

因此,不同的字符在计算机有不同的表示,也就是所谓的编码表。

计算机中存储信息的最小单元是一个字节即8个bit,所以能表示的字符范围是 0~255 个,人类要表示的符号太多,无法用一个字节来完全表示,要解决这个矛盾必须需要一个新的数据结构 char,从 char 到 byte 必须编码。这就是编码出现的原因。

那么字母”A”在硬盘上是如何存储的呢?

可能小张计算机存储字母”A”是1100001,而小王存储字母”A”是11000010,这样双方交换信息时就会误解。比如小张把1100001发送给小王,小王并不认为1100001是字母”A”,可能认为这是字母”X”,于是小王在用记事本访问存储在硬盘上的1100001时,在屏幕上显示的就是字母”X”。也就是说,小张和小王使用了不同的编码表。

为了让大家能够互相理解,大家需要采用统一的编码表。

UTF-8编码

那么为什么使用UTF-8编码呢?

ASCII

在所有字符集中,最知名的可能要数被称为ASCII的7位字符集了。它是美国标准信息交换代码(American Standard Code for Information Interchange)的缩写, 为美国英语通信所设计。它由128个字符组成,包括大小写字母、数字0-9、标点符号、非打印字符(换行符、制表符等4个)以及控制字符(退格、响铃等)组成。但是,由于他是针对英语设计的,当处理带有音调标号(形如汉语的拼音)的亚洲文字时就会出现问题。

Unicode

Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发,1994年正式公布。Unicode 只是一个符号集,它只规定了符号的二进制代码,没有规定这个二进制代码应该如何存储。

UTF-8

互联网的普及,强烈要求出现一种统一的编码方式。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。其他实现方式还包括 UTF-16(字符用两个字节或四个字节表示)和 UTF-32(字符用四个字节表示),不过在互联网上基本不用。

UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。


上面介绍了字符编码的一些知识,下面针对实际应用中遇到的两个问题的解决进行分析。

UTF-8 BOM

BOM是Byte order mark的缩写,一般作为标识出现在文本的首行。

因为在Windows平台下,默认不显示BOM,因此在读取文件、编译源码或者执行SQL的时候,很可能因为文件是UTF-8 BOM格式的,而产生错误。

例如简单的Test.java:

public class Test{}

如果保存为UTF-8 BOM格式,在编译的时候回出现如下错误:

# javac Test.java
javac: 找不到文件: Test.java
用法: javac <options> <source files>
-help 用于列出可能的选项

这就是因为文件是以Byte order mark开头导致的。

这种问题一般是怎么出现的呢?一般是由于在不同平台(例如Windows和Linux之间)、不同编辑器(例如邮件编辑、文本编辑)之间互相传文件造成的。

那么如何避免这个问题呢?答案就是通过编辑器仔细检查编码,或者用批量替换、过滤的方式,避免出现这种字符。

UTF-8 控制字符

控制字符(Control Character),出现于特定的信息文本中,表示某一控制功能的字符。

但是控制字符不能再XML中自由的转换,如果XML的内容出现了控制字符,会出现Unmarshalling Error

例如将一段用户输入的地址数据,通过Webservice接口传输的过程中,出现了如下异常,就是控制字符造成的:

webservice exception,
error message:
{}\norg.apache.cxf.binding.soap.SoapFault:
Unmarshalling Error:
Illegal character ((CTRL-CHAR, code 8))\n at [row,col {unknown-source}]: [201,32] \n\tat

简单的解决办法就是将控制字符进行转换:

  1. using guava:
return CharMatcher.JAVA_ISO_CONTROL.removeFrom(string);
  1. using regex:
string.replaceAll("\\p{Cntrl}", "");
  1. using apache commens
StringEscapeUtils.escapeXml10(string);


目录
相关文章
|
2月前
|
自然语言处理
字符编码
字符编码。
56 15
|
5月前
|
存储 自然语言处理 数据可视化
字符集编码(三):Unicode
中国的 GB 编码和日本的 JIS 编码在兼容 ASCII 的同时,又给 ASCII 中的可见字符做了个“全角”编码(原 ASCII 中的字符被称为“半角”字符)。所谓全角和半角字符,在字形和字意上都完全相同,只是全角字符占用宽度(注意不是字形本身的宽度)是半角字符的两倍(据说是为了中英文混排时的美观效果),按照 Unicode 的设计原则,这种问题应该交由文字渲染程序去处理,
53 1
|
存储 编解码 算法
字符编码的前世今生
字符编码的前世今生
178 0
|
存储 Java 关系型数据库
【技术干货】理解Unicode字符编码
本文对字符编码Unicode以及UTF8和UTF16的编码原理进行了详细说明
670 1
|
存储 编解码 Windows
理解字符编码
理解字符编码
理解字符编码
|
存储 自然语言处理 JavaScript
【字符编码】彻底理解字符编码
在解决昨天的问题时,又引出了很多新的问题,如为什么要进行编码,这些编码的关系如何,如ASCII,IOS-8859-1,GB2312,GBK,Unicode之间的关系,笔者想要彻底理解字符编码背后的故事,遂进行了探索,具体笔记如下。如园友能读完本篇文章,我相信会解开很多疑惑
300 0
【字符编码】彻底理解字符编码
|
存储 自然语言处理 JavaScript
【字符编码】彻底理解字符编码
 在解决昨天的问题时,又引出了很多新的问题,如为什么要进行编码,这些编码的关系如何,如ASCII,IOS-8859-1,GB2312,GBK,Unicode之间的关系,笔者想要彻底理解字符编码背后的故事,遂进行了探索,具体笔记如下。如园友能读完本篇文章,我相信会解开很多疑惑。
319 0
【字符编码】彻底理解字符编码
|
存储 自然语言处理
字符编码unicode,utf-8和ascii
Ascii编码 由于计算机是美国人发明的,因此,最早只有127个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号,这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122。
1106 0
|
JavaScript 前端开发 .NET