通俗易懂地解决中文乱码问题(1) --- 跨平台乱码

原文:【原创】通俗易懂地解决中文乱码问题(1) --- 跨平台乱码

本来是只打算写一篇关于中文乱码的blog的,但是发现要讲的东西跨度有点大,不好写到同一篇里面,所以分开了。

另一篇是  《【原创】通俗易懂地解决中文乱码问题(2) --- 分析解决Mysql插入移动端表情符报错 ‘incorrect string value: ‘\xF0...》 。

这一篇重点在编码的理论,另一篇重点在解决问题及思路。

一、问题的开始

中文乱码问题经常出现在实际工程中,尤其容易发生在经验不足的团队对问题预估不足的情况下。网站开发,社交聊天等对输入信息不可控的应用往往是重灾区。再加上移动互联网的火热,新兴字符和表情也开始频繁被使用,如果不能达到足够的支持,对用户体验来说是个灾难。所以,在设计系统的开始,要严格把控字符编码。以大体明确怎么做是不会出错的(严格按规则限制往往难以把控,并且容易漏掉被钻空子,所以做到不出错是出发点)。

二、Unicode

Unicode是本文的重点。

Unicode是一种通用字符集,是对字符的定义。和之对应的也有,比如 ISO 8859-1。但Unicode被广泛使用并成为业界的标准,所以我们可以认为Unicode就是对计算机里字符的定义,在内存中的表现是0,1串。

而且,Unicode的编码很干净,它为 字符而非字形定义唯一的代码。换句话说,统一码以一种抽象的方式(即数字)来处理字符,并将视觉上的演绎工作(例如字体大小、外观形状、字体形态、文体等)留给其他软件来处理,例如网页浏览器或是文字处理器。举个例子,如 “ɑ/a”、“強/强”、“戶/户/戸”。(引自wiki)

这样,Unicode本身要做的任务很明确,就是合适的扩充编码。

三、UTF-8

UTF-8是Unicode的一种实现方式,是可变长的字符编码。与之对应的还有GBK(固定长度),Latin,UTF-16(Unicode的完全式)等等。

这些为什么是实现方式呢?不是Unicode已经定义好了吗?其实这也是计算机学科经常用的方法,这些不同的编码就类似于针对Unicode的各种trick。

举个简单的例子,一个整形数组A[],那么给A[]排序这个定义就相当于Unicode。那么是采用快排、堆排还是归并,用正序还是倒序排列结果,这些方法就相当于编码格式。而这些都是对这个定义的具体实现过程,但是方法不同。

因此,不论是UTF-8、GBK、Latin等,其还原的编码结果都是同一个Unicode编码。

四、Unicode和UTF-8的关系及转换过程

那么对于Unicode和UTF-8的关系,可以用上面的例子理解。不过真实情况应该是类似下面这样的。

比如"国"字的Unicode编码定义为 00000000 00000000 00110100 11000000 (假设)。

由于其低16位都是0,为了减少存储和传输这个字在字节上的浪费,就选择高16位来表示。同时由于UTF-8是可变长的,所以需要标识位来标识这个编码到底使用了几个字节。

所以 “国”字 对应的 UTF-8的编码应该是 11100011 10010011 10000000(加粗的是原编码的高16位)。

转换公式:1110xxxx(E0-EF) 10yyyyyy 10zzzzzz,显示标明的是标志位)。

以下附上UTF-8的编码方式:(引自wiki)

五、中文跨平台乱码及解决办法

有了以上知识的积累,我们可以分析为什么跨平台会出现乱码?明明好好的Unicode怎么就乱了呢?

那么很直观我们会想到应该是编码格式不兼容

对于windows平台,编码格式是GBK,对应的汉字是两个字节长度。对于Linux平台,编码格式是UTF-8,对应的汉字是3个字节。(这里都是默认情况)

那么我们还用上面 排序这个例子来解释。

比如现在Unicode用 {1,2,3}定义,GBK代表正序排列,UTF-8代表倒序排列。那么现在Unicode在GBK下的编码是{1,2,3},在UTF-8下的编码是{3,2,1}。

现在由GBK编码还原Unicode编码,那么正向解析GBK就是Unicode。而由UTF-8编码还原Unicode编码,需要逆向解析UTF-8编码。这都是和自身对应的。

但是如果一个把GBK编码误认为是UTF-8,那么逆向解析后的结果是{3,2,1}。首先这个结果不是原始的Unicode编码,那么其转换的结果不是我们需要的。其次,很可能这个编码结果在Unicode中还没有定义,可能会出现类似空格一样的空白符。

因此这就是跨平台中文乱码的原因,编码和解码方式出现了差别。

解决办法:

解决办法其实有很多种,根据自身应用的不同既可以选择在代码端进行编码的转换(比如java的 String str = new String(str.getBytes("GBK"), "UTF-8");),也可以在输入端进行编码格式的调整。

不过归结下来只有一点,即 如果当前输入是GBK编码,而你需要的又是UTF-8编码,那么:

1. 用GBK的解码方式转换成Unicode。

2. 使用UTF-8编码进行编码。

六、中文编码一些有趣的应用

这里我只想到了11游戏对战平台上面一些搞笑的名字(一不小心貌似暴露了什么。。不过很久不玩11了),后面想到其它还会更新的。

比如下面这个图:

蓝圈里面的玩家名字是正常显示的,为绿色。红圈里面的是蓝色,相当于突破了11客户端的限制显示了其它特殊颜色。

这个做法就是对应名字后面加上|r。这是一个转义符,合理的利用了11平台给用户开放的字符集并产生了特殊效果。所以这也是我开篇说的严格把控字符集是很难的,控制到不出错(比如系统乱码)已经挺好了。

转载请注明出处,谢谢~  http://www.cnblogs.com/xiaoboCSer/p/4175361.html

时间: 2024-10-23 21:28:32

通俗易懂地解决中文乱码问题(1) --- 跨平台乱码的相关文章

【原创】通俗易懂地解决中文乱码问题(2) --- 分析解决Mysql插入移动端表情符报错 ‘incorrect string value: '\xF0...

这篇blog重点在解决问题,如果你对字符编码并不是特别了解,建议先看看 < [原创]通俗易懂地解决中文乱码问题(1) --- 跨平台乱码 >. 当然,如果只是针对解决这个Mysql插入报错问题,本篇足够了. 一.定位错误 定位错误绝对是至关重要的一环.我建议遇到问题耐心分析一下比较好,毕竟“不是所有的牛奶都叫特仑苏”. 引起同一个问题的可能有很多,别人的解决方案也许并不适合自己. 那先看看问题出现在哪了,报错如下: 发现的确是编码错误, 16进制的错误提示(\xF0\x9F\x94\xA5\x

通俗易懂地解决中文乱码问题(2) --- 分析解决Mysql插入移动端表情符报错 ‘incorrect string value: &#39;\xF0...

原文:[原创]通俗易懂地解决中文乱码问题(2) --- 分析解决Mysql插入移动端表情符报错 'incorrect string value: '\xF0... 这篇blog重点在解决问题,如果你对字符编码并不是特别了解,建议先看看 < [原创]通俗易懂地解决中文乱码问题(1) --- 跨平台乱码 >. 当然,如果只是针对解决这个Mysql插入报错问题,本篇足够了. 一.定位错误 定位错误绝对是至关重要的一环.我建议遇到问题耐心分析一下比较好,毕竟“不是所有的牛奶都叫特仑苏”. 引起同一个问

cocos2d-x封装一个转码的工具解决中文乱码可以直接拖过去用通用跨平台

今天白白给大家分享一个转码的工具函数,如果大家需要在项目中显示中文,可以直接使用,Android和IOS部分都是通用的,不用太麻烦的分平台操作. 转载请注明地址http://blog.csdn.net/u010229677 首先,这个函数是这样的,可以直接拖进去用 <span style="font-size:18px;"><span style="font-size:18px;">#ifndef __TRANSFORMUTF__ #defi

Cocos2d-x 3.1.1 学习日志4--cocos2d-x解决中文乱码问题的几种办法

做个打飞机的游戏,由于版本太新,网上基本没有教教程,我的版本是cocos2d-x 3.1.1的,今天遇到cocos2dx中中文乱码的问题.无奈只好Google百度寻求答案,明白了这个问题的缘由.因为cocos2d-x内部是以utf8处理文本的,而VS直接输入时文本编码为GBK,如果添加L标志,则为Unicode编码. 解决这个问题有三种办法: 将源代码文件保存为utf8编码,不过由于编译器的问题,这种方式会导致很多无法预测的问题 将字符串用utf8编码集中存到一文件中,然后用代码读取这些字符串来

linux基础-zabbix解决中文乱码问题 (因为版本太新的问题,没有测试成功)

zabbix解决中文乱码问题 1.在windows系统中找一个自己喜欢的字体,这里我们用:msyh.ttf 2.将字体上传至/var/www/html/zabbix/fonts目录下 [[email protected] ~]# cd /var/www/html/zabbix/fonts/ [[email protected] fonts]# rz -yrz waiting to receive.???a? zmodem ′???£ °′ Ctrl+C ???£??′?? msyh.ttf...

解决中文乱码过滤器

解决中文乱码过滤器 import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse;

java解压多目录Zip文件(解决中文乱码问题)--转载

原文地址:http://zhangyongbo.iteye.com/blog/1749439 import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Enumeration; import org.apache.tools.zi

javaEE:day2-servlet生命周期、提交解决中文乱码、tomcat加载jar包或类文件的顺序

servlet生命周期 生命周期简介: servlet在服务器第一次被请求的时候new出来,并初始化(即init())再调用service方法.这个实在服务器中new出来,然后用HashMap加的,与客户端无关.客户端之后访问只调用这个servlet的service方法. 具体分为4步: 1 构造方法 :服务器在被客户端第一次请求的时候运行 仅在服务器中运行一次 2 init方法:客户端第一次访问服务器的时候在服务器中进行初始化 仅一次.并且可以通过config参数在 web.xml中通过(ke

HttpServletRequest解决中文乱码的问题

HTTP请求有get和post,这两中方式解决中文乱码的方式如下: 1.Post方式请求 //这句话是设置post请求体的编码为utf-8 request.setCharacterEncoding("utf-8");//获取请求参数 request.getParameter("username"); 2.Get方式请求 new String(request.getParameter("username").getBytes("ISO-8