2019-12-22

ASCII,GB2312,GBK,Unicode,UTF-8字符编码到底是什么?

  • 谈到这个问题就不得不说在编码过程中遇到的乱码问题,我想这应该是每一个程序员都头疼的问题。
    首先,我们需要思考:
    一. 什么是字符?

字符指类字形单位或符号,包括字母、数字、运算符号、标点符号和其他符号,通常由8个二进制位(一个字节)来表示一个字符。 字符是计算机中经常用到的二进制编码形式,也是计算机中最常用到的信息形式。

二.什么是字符集?

字符集简单来说就是字符的集合,它的种类比较多,每种字符集包含的字符个数不同,常见字符集有:ASCII字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。

三.什么是字符编码?

字符编码也称字集码,是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。常见的例子包括将拉丁字母表编码成摩斯电码和ASCII。其中,ASCII将字母、数字和其它符号编号,并用7比特的二进制来表示这个整数。通常会额外使用一个扩充的比特,以便于以1个字节的方式存储。

  • 好了,了解这些基础知识后,我们可以进一步了解常见的字符编码

ASCII

  • 我们应该清楚电脑中所有数据其实都是二进制数据,电脑真正能识别的只有0和1,1byte = 8bit,因此总共有2^7=128种表示方式,包括32个字符,其余96位为英文字母和标点符号及运算符号等,其二进制表示范围为00000000-01111111。


    ASCII字符集

GB2312

  • GB2312 是最早一版的中文编码,每个字占据2bytes。由于要和ASCII兼容,所以2b字节最高位不可以为0了(否则和ASCII会有冲突)。在GB2312中收录了6763个汉字以及682个特殊符号,已经囊括了生活中最常用的所有汉字。每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”,第二个字节称为“低位字节”,“高位字节”使用了0xA1-0xF7(把01-87区的区号加上0xA0),“低位字节”使用了0xA1-0xFE(把01-94加上 0xA0)。 由于一级汉字从16区起始,汉字区的“高位字节”的范围是0xB0-0xF7,“低位字节”的范围是0xA1-0xFE,占用的码位是 72*94=6768,其中有5个空位是D7FA-D7FE。(摘自百度百科,了解即可)

GBK

-GBK编码,是在GB2312标准基础上的内码扩展规范,使用了双字节编码方案,其编码范围从8140至FEFE(剔除xx7F),共23940个码位,共收录了21003个汉字,完全兼容GB2312标准

Uncoide

  • Unicode是计算机科学领域里的一项业界标准,包括字符集、编码方案等,它可以容纳世界上所有文字和符号,Unicode为世界上所有字符都分配了一个唯一的数字编号,这个编号范围从 0x000000 到 0x10FFFF(十六进制),有110多万,每个字符都有一个唯一的Unicode编号,这个编号一般写成16进制,在前面加上U+。具体的符号对硬表可以查看官网

UTF-8

  • UTF-8可以说是我们最常用的编码格式了,之前的Uncoide功能确实强大,包含了世界的所有文字和编号,但它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储,直到互联网的普及催生了UTF-8编码方式。
    UTF-8 的编码规则很简单,只有二条:
    1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。

    2. 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

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
  • 跟据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。
    列:
public static void main(String[] args) throws UnsupportedEncodingException {
        String s = "汉";
        byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
        for (byte b:bytes){
            System.out.println("该字节的十进制数str是 : " + b);
            System.out.println("该字节的2进制数str是 : "+ (Integer.toBinaryString(b)+""));
            System.out.println("该字节的16进制数是 : U+"+ (Integer.toHexString(b)+""));
        }
    }

结果:

该字节的十进制数str是 : -26
该字节的2进制数str是 : 11111111111111111111111111100110
该字节的16进制数是 : U+ffffffe6
该字节的十进制数str是 : -79
该字节的2进制数str是 : 11111111111111111111111110110001
该字节的16进制数是 : U+ffffffb1
该字节的十进制数str是 : -119
该字节的2进制数str是 : 11111111111111111111111110001001
该字节的16进制数是 : U+ffffff89

由此可见汉是由三个字节组成的,其二进制是11100110 10110001 10001001,转换成16进制为e6b189;

  • 针对对常见乱码问题怎样解决?
    乱码一般都是string字符串转换错误引起的,我们需要首先了解下string常用的两个编码转换方式getBytes(Charset charset)和new String(byte[] bytes,Charset charset)
/**
     * Encodes this {@code String} into a sequence of bytes using the given
     * {@linkplain java.nio.charset.Charset charset}, storing the result into a
     * new byte array.
     *
     * <p> This method always replaces malformed-input and unmappable-character
     * sequences with this charset's default replacement byte array.  The
     * {@link java.nio.charset.CharsetEncoder} class should be used when more
     * control over the encoding process is required.
     *
     * @param  charset
     *         The {@linkplain java.nio.charset.Charset} to be used to encode
     *         the {@code String}
     *
     * @return  The resultant byte array
     *
     * @since  1.6
     */
    public byte[] getBytes(Charset charset) {
        if (charset == null) throw new NullPointerException();
        return StringCoding.encode(charset, value, 0, value.length);
    }

 /**
     * Constructs a new {@code String} by decoding the specified array of
     * bytes using the specified {@linkplain java.nio.charset.Charset charset}.
     * The length of the new {@code String} is a function of the charset, and
     * hence may not be equal to the length of the byte array.
     *
     * <p> This method always replaces malformed-input and unmappable-character
     * sequences with this charset's default replacement string.  The {@link
     * java.nio.charset.CharsetDecoder} class should be used when more control
     * over the decoding process is required.
     *
     * @param  bytes
     *         The bytes to be decoded into characters
     *
     * @param  charset
     *         The {@linkplain java.nio.charset.Charset charset} to be used to
     *         decode the {@code bytes}
     *
     * @since  1.6
     */
    public String(byte bytes[], Charset charset) {
        this(bytes, 0, bytes.length, charset);
    }
  • getBytes(Charset charset)方法表明的很清楚,用给定的字符编码生成字节数组,并将结果放入新数组里,简单来说就是把我们认识的字变成一连串不认识的编码符;new String(byte[] bytes,Charset charset)通过给定字符编码解码数组并构造新的字符串,简单来说就是把我们不认识的字符变成我们熟悉的字。因此,常见解决办法主要有以下几种:
1.
String  msg =  request.getParameter("message");
String  str =  new String(msgs.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8)
2.
request.setCharacterEncoding("UTF-8");
3.
  在你的web.xml里加入如下几行:  
 <filter>   
  <filter-name>CharacterEncoding</filter-name>   
  <filter-class>filters.SetCharacterEncodingFilter</filter-class>   
  <init-param>   
  <param-name>encoding</param-name>   
  <param-value>UTF-8</param-value>   
  </init-param>   
  </filter>   
      <filter-mapping>   
  <filter-name>CharacterEncoding</filter-name>   
  <url-pattern>/*</url-pattern>   
  </filter-mapping>   
4.
 打开tomcat的server.xml文件,加入如下一行:URIEncoding=“UTF-8"
  完整的应如下:   
  <Connector     
  port="80"   maxThreads="150"   minSpareThreads="25"   maxSpareThreads="75"   
  enableLookups="false"   redirectPort="8443"   acceptCount="100"   
  debug="0"   connectionTimeout="20000"     
  disableUploadTimeout="true"     
  URIEncoding="UTF-8"   
  />      

原创不易, 如需转载,请注明出处!
——纯生啤酒_

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容