精华内容
下载资源
问答
  • 他可能是手势,可能是凸起的文字,甚至可以是光的闪烁/明暗(摩尔斯电码),它只是一种交流的工具。 那么什么是什么样的语言计算机可以理解。 对我们而言,10是一个重要的数字。10是大多数人拥有的手指或者...

     

    -------最大的勇气不是坚持,而是从头再来

    <0>序言

    从刚开始的懵懂,到现在的糊里糊涂,是时候结束自己的状态,毕竟青春所剩的不多了。最大的勇气不是坚持,而是从头再来。

    正如计算机的数组下标从0开始,我们的内容也从0开始。从我们那些年丢失的基础,一点一滴的开始重修。

    大方无隅,大道无形,最复杂的理论可以用最简单的方式描述。那么什么是编程。就是编写程序。那么什么又是程序。在日常生活中,一般所说的程序,指的是“行事的先后顺序”,在计算机的世界中,也是一样的道理。程序是指令和数据的组合体。

    <0.1>计算机的启动过程

    当你第一次接触计算机,可能第一件事,就是熟悉计算机的开关机。我们可能只是按下主机的power键,并且打开显示器,在各种线路都接完毕时,我们在稍等就会看到windows的GUI了/CLI (Linux大神请自行忽略本文)。那么真实的过程真的是这么简单么?

    第一棒:BIOS (Basic Input Output System)

    BIOS是位于主板上的一个小程序,是计算机在接电之后运行的基本输入输出系统。因为它的空间有限,它只是一些简单的检测或初始化工作,然后把接力棒交出去,侠义榜的选手是MBR。

    第二棒 MBR (Master/Main Boot Record )

    MBR是主引导记录。它存在整个硬盘最开始的那个扇区(0盘0道1扇区),这个扇区便称为MBR引导扇区。注意这里用CHS方式表示MBR引导扇区的地址,因此扇区的地址以1开始,顺便说一下LBA方式是以0为开始为扇区编址的。

    在MBR引导扇区中的内容是:(1)引导程序以及参数(2)分区表(3)结束标记

    既然MBR称为主引导程序,那么就会有次。通常这个次引导程序就是操作系统提供的加载器,因此MBR引导程序就是把控制权继续交接给加载器。加载器完成操作系统的自举,最终使控制权交付给操作系统。MBR中的分区表就包含次引导程序的候选人群。

    第三棒 OBR(OS Boot Record)

    为了MBR方便的找到活动分区上的内核加载器,内核加载器的入口地址必须固定,这个位置就是各个分区最开始的扇区,在这里存放着操作系统的引导程序-------内核加载器。因此被称为操作系统引导扇区,其中引导程序称为OBR。

    第四棒 OS

    操作系统的相关描述以及功能会在之后的小结中介绍。

    这些就是隐藏在一个POWER键后的一些列操作,其实并不是很简单。

    <0.2>计算机的语言

    语言是什么?它是一个交流的工具。它不仅仅局限于我们所说的汉语,英语,法语等。他可能是手势,可能是凸起的文字,甚至可以是光的闪烁/明暗(摩尔斯电码),它只是一种交流的工具。

    那么什么是什么样的语言计算机可以理解。

    对我们而言,10是一个重要的数字。10是大多数人拥有的手指或者脚趾的数目。因为手指非常便于技术,于是我们已经适应了这个以10为基数的数字系统。

    那么对于电子设备来说,由于电压的有可能不稳定,索性直接用有电,无电带表达或者说是交流,也就是0,1(不全是,还有用真空管排列达到十进制的效果)。0,1这种二进制数字系统就成为了计算机世界中的语言。

    接下来,正式走进计算机的世界。

     

     

     

    转载于:https://my.oschina.net/BElement/blog/849436

    展开全文
  • 你完全可以自己设计出一套符号系统,用来表达,你想表达的含义,摩尔斯电码和盲文就是很好的例子。 数学,也是一种语言,某知名高数教材,面向大一新生直接引入极限的精确定义,使得初学者无法理解背后的本质,学...

    df08758f4125

    我对上帝说西班牙语,对女人说意大利语,对男人说法语,对我的马说德语。

    ——法国国王查理五世(1500——1558)

    首先,让我们先来玩个记忆游戏,请你仔细地浏览这张图,并尽可能记住所有的细节。仔细浏览的意思是说,从上至下,从左至右,从实线到虚线,每一个字、每一幅图都仔仔细细地看一遍。

    df08758f4125

    自然 - 语言 - 符号

    吾爱汝。

    我愛你。

    I love you.

    Te amo.

    上面四句话,是什么意思?换句话说,它背后的本质是什么?相信你一定懂得第一句和第二句话,即便你不懂第四句话,但通过前三句话,你也一定知道第四句话表达的是同样的意思——“我爱你”——就是这四句话的本质,它们唯一的区别是符号不同。

    发现了吗?文字仅仅只是一种符号,光是看着 Te amo 这些符号的组合,你什么都不明白,也什么都做不了。只有当你把Te amo背后的那个“东西”与前面三个等同起来,它才有了意义和本质。

    你完全可以自己设计出一套符号系统,用来表达,你想表达的含义,摩尔斯电码和盲文就是很好的例子。

    数学,也是一种语言,某知名高数教材,面向大一新生直接引入极限的精确定义,使得初学者无法理解背后的本质,学起来必然痛不欲生。

    机器语言与动物语言

    小猫喵喵喵喵,小狗汪汪叫,语言学家和动物学者可能会说小动物不会语言。我不这么认为,难道发不出26个汉语拼音,英文字母的音就无法交流吗?实际上,小动物才是真正的交流高手。高手过招往往都是点到为止,因此小动物的交流也很简单,吃、喝、拉、睡——一个动词,无需多余的编码(code)组合就能表达完所有意思,且不会造成歧义,快捷又高效。

    编码(code)

    a. 一种在信息传输过程中用来表述祖母或数字的信号系统。

    b. 由被赋予了一定主观意义的符号、字母以及单词所组成的系统,该系统可用于传输需要保密或简短的信息。

    c. 一种由若干符号和规则组成的系统,用来向计算机表述指令。

    相比之下,我们的语言就复杂得很多了,一说到学习英语,一些人就会苦恼,小的时候记26个字母的发音、写法,再大一点要记住它们的排列组合,也就是编码,再来还有它们的语法规则,主、谓、宾、定、状、补、从句……甚至人类的语言还有很多的“噪音”,歧义重重——往往越解释,越不清楚,越描越黑。

    被误解是表达着的宿命。

    ——马东《奇葩说》

    20世纪40年代末,第一台计算机诞生了,随着计算机的出现,一种新的语言也诞生了,叫做机器语言(machine language)。程序员使用这种语言编写程序,输入到计算机中,经过计算机的处理,产生结果再返还给程序员。机器语言(也称机器指令、机器码)是计算机可以直接识别的二进制位(binary digit)编码,之所以采用二进制,因为电路的电压便于用“高”和“低”两种状态来表示,就像这样:

    10001100 10100000 // A加B

    同样的它们都是符号,一旦经过设计和编码,就可以表达特定的含义。

    和小动物一样,计算机也有基本的需求——做算术运算。“0”和“1”经过编码,就可以做出加、减、读、写等基本操作了。

    但是,编程人员很快就发现了——作为人类自身的不足,用两种状态表达计算过程,容易出错,记忆困难,不便阅读,编写起来十分枯燥。

    机器语言(machine language):以二进制形式表示的机器指令。

    二进制位(binary digit):也成为位。基数为2的数字中的0或1,它是信息的基本组成元素。

    汇编语言

    程序员认识到这个问题,很快就设计出了汇编语言(assembly language),利用助记符来编写程序,顾名思义,是帮助编程人员记忆的符号语言。

    add $t0, $s0, $s1 // 将寄存器$s0的值和$s1值相加,赋值给$t0

    add $t1, $s2, $s3 // 将寄存器$s2的值和$s3值相加,赋值给$t1

    sub $t0, $t0, $t1 // 将寄存器$t0的值和$t1值相减,赋值给$t0

    但是根本问题依旧没有解决,计算机懂的是机器语言,不是汇编语言,因此每次使用汇编语言编写完程序后,还是需要程序员翻译为机器语言,这时,汇编器(Assembler)就诞生了,它充当翻译官的角色,将汇编语言翻译为机器语言。

    由于汇编语言与机器语言十分接近,机器语言与汇编语言又统称为低级语言。虽然助记符比机器语言要容易记忆,但用它编写程序依旧十分繁琐,编程人员必须将注意力和时间消耗细节上,告诉计算机每一条指令的执行:第一步从内存的某一个位置取一个数,第二步加到某个寄存器中,第三步再……这些工作,费时费力,因此产生了新的需求。

    汇编语言(assembly language):以助记符形式表示的机器指令。

    汇编器(Assembler):也叫汇编程序,将指令由助记符形式翻译成二进制形式的程序。

    高级语言与自然语言

    记忆、阅读与理解起来困难,不符合人类的认知规律,高级语言应运而生。只要你学过四则运算,和初等代数,你就一定能理解下面这句话在做什么,满足了什么样的需求。

    a = (b + c) – (d + e);

    这段代码,和上面的汇编代码本质所做的事,满足的需求,所表达的含义是等同的,却更符合,人类的认知,容易记忆。

    高级语言:如C、C + +、Java、Visual Basic等可移植的语言,由一些单词和代数符号组成,可以由编译器转换为汇编程序。

    编译器:将高级语言翻译为计算机所能识别的机器语言的程序。这个过程相当复杂,不作过多介绍。

    高级语言与低级语言在某些方向上是一致的,因为其本质的工作,所需要完成的任务本质上并无变化,不外乎要做基本的运算,所有的高级语言都有基本的运算符号,运算规则:

    I love you.

    She needs me.

    They eat hamburgers.

    人也有基本的需求,我爱你,我需要你,我吃汉堡,我喝可乐。语法老师在教你时,肯定会告诉你:

    I 是 主语

    love 是 动词

    you 是 宾语

    一个完整的句子必须有动词,同时你必须按照主+谓+宾的顺序来听说读写,那是因为“我”和“你”本身本无任何联系,“她”和“我”本身并无联系,“他们”和“汉堡”也无联系,而 love, need, eat 产生了动作,才使得他们产生了联系。自然语言中 I, you, she, me, they, hamburger 归类为名词,在编程语言中我们把它们称为类型。我们用编程语言的形式,可以将上面的三句话改写为:

    love(I, you);

    she(needs, me);

    eat(they, hamburgers);

    这时 I, you, she, me, they, hamburger 也叫作参数。love, she, eat 表示它们所完成的动作,称为函数。

    汉语和英语相比较而言,英语有16种时态变化,我们在学习与理解不同的语言时,要注重的是它们的共性与特性:

    词性(名词,动词,形容词,副词···)

    句子结构(主+谓+宾···)

    ···

    同样的,学习现代编程语言,也需要去学习和理解它们的特性:

    面向过程

    面向对象

    变量定义、引用

    算术运算

    函数定义、调用

    ···

    一部分初学者,甚至某些已经学过编程语言的人,还纠结于在选择什么样的编程语言这种问题上,是不正确的。

    学习、理解或者掌握一门编程语言别无他法,就是学会使用其语言的特性,编写出一定数量的代码,像学英语一样仅仅靠背语法规则,但从不去使用在听、说、读、写上是行不通的。

    更重要的是,带着问题,带着目的去运用语言。

    后记

    还记得开篇的图吗?同样的,与汇编语言一样,机器永远只能识别二进制,无法识别高级语言,我们需要将高级语言先转化为汇编语言,编译器就是用来翻译高级语言的。

    我已经带着你遍历了自然语言、低级语言甚至是动物语言,希望看完之后你对所有的语言都有了更进一步的认识。

    为了便于初学者学习,基本上已在文中出现的计算机相关术语下方,给出了较为准确的解释,希望可以帮助初学者更好的理解这些专业术语。

    感谢阅读,全文完,喜欢记得关注打赏

    版权所有,禁止转载

    展开全文
  • 1 class Student { 2 static String[] ss = new String[]{"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}; 3 static String[] mm = new String[]{"仟", "佰", "拾", ""}; 4 static Stri...
     1 class Student {
     2     static String[] ss = new String[]{"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
     3     static String[] mm = new String[]{"仟", "佰", "拾", ""};
     4     static String[] hh = new String[]{"", "萬", "亿", "兆","京","垓"};
     5 
     6     int dd = 123456789;
     7 
     8     public static void main(String[] args) {
     9         read("22222222222222222222222");
    10     }
    11 
    12     private static void read(String num) {
    13         String[] strings = num.split("\\.");
    14         String integer = strings[0];
    15         String zhengs =readInteger(integer);
    16         String xiaos="";
    17         if(strings.length==2){
    18             String decimal = strings[1];
    19              xiaos="点"+readDecimal(decimal);
    20         }
    21         String xx=zhengs+xiaos;
    22         System.out.println(xx);
    23     }
    24 
    25     private static String readInteger(String integer) {
    26         int mark = integer.length();
    27         int star = mark - 4 < 0 ? 0 : mark - 4;
    28         int end = mark;
    29         StringBuilder stringBuilder = new StringBuilder();
    30         for (int i = 0; i <= integer.length() / 4; i++) {
    31             String nn = integer.substring(star, end);
    32             mark=star;
    33             star = mark - 4 < 0 ? 0 : mark - 4;
    34             end = mark;
    35             String nn1 = readfour(nn);
    36             if (!nn1.equals("")) {
    37                 stringBuilder = stringBuilder.insert(0,nn1 + hh[i]);
    38             }
    39 
    40         }
    41         if(stringBuilder.charAt(0) == '零'){
    42             stringBuilder.replace(0, 1, "");
    43         }
    44         return stringBuilder.toString();
    45     }
    46 
    47     private static String readDecimal(String decimal) {
    48         StringBuilder stringBuilder = new StringBuilder();
    49         for (int i = 0; i < decimal.length(); i++) {
    50             stringBuilder.append(ss[Integer.parseInt(decimal.charAt(i) + "")]);
    51         }
    52         return stringBuilder.toString();
    53     }
    54 
    55     private static String readfour(String nn) {
    56         StringBuilder stringBuilder = new StringBuilder();
    57         int d=4-nn.length();
    58         if(d!=0){
    59             for (int i = 0; i <d ; i++) {
    60                 nn="0"+nn;
    61             }
    62         }
    63         for (int i = 0; i < nn.length(); i++) {
    64             if (nn.charAt(i) == '0') {
    65                 stringBuilder.append(ss[Integer.parseInt(nn.charAt(i) + "")]);
    66             } else
    67                 stringBuilder.append(ss[Integer.parseInt(nn.charAt(i) + "")] + mm[i]);
    68         }
    69 
    70         //多个零变一个零
    71         for (int i = 0; i < stringBuilder.length(); i++) {
    72             if (stringBuilder.charAt(i) == '零') {
    73                 if((i+1)==stringBuilder.length())
    74                     continue;
    75                 if (stringBuilder.charAt(i + 1) == '零') {
    76                     stringBuilder.replace(i + 1, i + 2, "");
    77                     i=i-1;
    78                 }
    79             }
    80         }
    81         //去掉末尾的零
    82         if (stringBuilder.charAt(stringBuilder.length() - 1) == '零') {
    83             stringBuilder.replace(stringBuilder.length() - 1, stringBuilder.length(), "");
    84         }
    85 
    86         return stringBuilder.toString();
    87     }
    88 
    89 
    90 }

     

    转载于:https://www.cnblogs.com/hxz-nl/p/10929983.html

    展开全文
  • 字符编码的前世今生

    2020-10-29 10:39:09
    字符编码的前世今生摩尔斯电码ASCII码ANSI编码GB2312GBKGB18030UnicodeUTF-8UTF-16UTF-32Mysql 之 utf8mb4乱码(锟斤拷)是怎样炼成的 老板,给我上一窝锟斤拷 想必我们在刚刚接触代码开发时,都会接触到一个叫做...

    老板,给我上一窝锟斤拷

    想必我们在刚刚接触代码开发时,都会接触到一个叫做ASCII的东西,而初代的Java工程师们,可能在用eclipse的时候,会经常需要手动切换代码编码格式(从UTF-8到GBK),为的就是能够看清别人的代码注释,又或者,你知道手持两把锟斤拷,口中疾呼烫烫烫的由来么

    甚至出现了下图的一个场景

    在这里插入图片描述

    你知道为什么会 ”烫“ 会直击程序员本质么?

    今天我们就来给大家讲讲关于字符编码的前世今生。

    摩尔斯电码

    话说公元前1837年(公元个鬼啊没有公元),为了实现远距离传输信息这个需求(发电报),美国有位科学家发明了一种叫做摩尔斯电码的东西。它是一种时通时断的信号代码,通过不同的排列顺序来表达不同的英文字母、数字和标点符号。

    在这里插入图片描述

    摩尔斯电码由短的和长的电脉冲(称为点和划)所组成。点和划的时间长度都有规定,以一点为一个基本单位,一划等于三个点的长度。正好对应上电报的"滴"和"答"。正如上图所示,正是因为有人对摩尔斯电码进行了如图中的规定。某一种组合方式代表一定的数字或字母,并且大家都承认,才让这种方式得以广泛使用。

    我们经常看到的一些谍战剧,或者一些电影大片中(比如之前韩国很火的那部《寄生虫》),主角&配角急中生智,为了不轻易暴露自己的信息,或者迫于环境无法使用声音进行沟通,就会通过一些媒介向别人传播神秘的摩斯电码。

    其中的发报员需要将要表达的信息转换为对应的摩斯密码(这个过程称为字符编码),然后收报员再将收到的电码解释为原本的信息(字符解码),倘若他们没有使用一份完全相同的摩斯电码表,那么就会出现信息传递出错的严重问题。

    现在我们知道了上上个世纪是可以通过电报来进行传递信息的。那么到了我们的电脑时代呢?根据冯诺依曼体系:数字计算机的数制采用二进制;计算机应该按照程序顺序执行。

    而二进制,就是只有0和1两个数值,类似于摩尔斯电码的滴和答,但是没有那种停顿或者长度的表示,一切只能利用这两个数值去组装。

    于是乎,科学家们把一个0或者1占用的空间称为一个比特位。那么为了表示我们的十进制0-9,就用了4个比特位来进行表示。举个例子(实际不是这样好):用0000表示0,0001表示1,0010表示2…1001表示9,中间的也是依次类推,于是乎便有了二进制的说法。

    但是我们的计算机当然不会说仅仅只是用来做简单的数字加减,还希望能够存储一些字母,程序符号,控制字符等(合起来共计128个,用0~127表示)的功能。这个时候科学家就需要更多的比特位来表示这些信息。

    此时,美国科学家经过它们的初步统计,大概是有128个字符需要存储,那么根据二进制来算,7bit便足够代表以上所有的信息(2的7次方=128)。但是还有一个符号位(奇偶校验位)要放在哪里呢?就放在最高位吧,这样就组成了8个比特位。

    于是乎,在上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定,这被称为 ASCII 码,一直沿用至今。在ASCII表出来后,为了统一方便,此时大家就说把 8bit表示出来的值叫做字节(byte) 吧,于是就有了字节这个单位。这个时候便有了1Byte=8bit的定义。

    这个地方要提一下,ASCII是由95个可打印字符(0x20-0x7E)和33个控制字符(0x00-0x1F,0x7F)组成共计128个字符组成。

    控制字符是什么呢?就是当年用来直接控制一些设备去执行指定命令工作的,比如一旦终端、打印机遇上这些字节被传过来时,就要做一些约定的动作。于是打印机会打印反白的字了(0x1b…),会换行(0x10)了,终端会嘟嘟(0x07)叫了,有色彩(0x1b…)了。

    可打印字符就包括了所有的空格、标点符号、数字、大小写字母。

    ASCII码

    在这里插入图片描述

    ASCII 码表被发明之后,美国的科学家认为挺完美的了,毕竟计算机是美国人发明的,他们当时哪里用得着去管世界上其他国家的文字。在整个欧洲的拉丁语系中,没有一种语言的字母会超过128个,所以当时看确实是足够了。后来计算机在全世界的范围内得到了极大发展和普及,可是计算机却只能使用英语,人们不能使用自己的母语,所以各个国家和地区便根据自己的国家语言,制定了不同的标准,这个就是ANSI编码

    ANSI编码

    ​ ANSI编码是一种对ASCII码的拓展:ANSI编码用0x00~0x7f (即十进制下的0到127)表示 原有的ASCII字符,超出127的 0x80~0xFFFF 范围来表示其他语言的其他字符。也就是说,ANSI码仅在前128(0-127)个与ASCII码相同,之后的字符全是某个国家语言的所有字符。值得注意的是,上面的0xFFFF是涉及到第二个字节的空间的了,两个字节最多可以存储的字符数目是2的16次方,即65536个字符,这对于大部分的语言字符来说,绝对够了。

    ​ 值得注意的是, ANSI 编码之间是互不兼容,比如在日本的Windows系统中,ANSI 编码代表 Shift_JIS 编码,它是无法与中国的GB2312等兼容的。

    ​ 在我们国家,中国汉字博大精深, 当代的《汉语大字典》(2010年版)就收字60,370个,所以在遵循ANSI编码的情况下,一个字节是完全无法满足我们的汉字要求的,但是两个字节就非常够了,所以中国人就开始了定义自己的字符编码。

    GB2312

    中国国家标准简体中文字符集

    ​ 在1980年,中国推出了GB2312,这是16位字符集,即采用双字节编码。收录有6763个简体汉字,682个符号,共7445个字符;

    ​ 在设计GB2312时,中国也不敢说完全脱离老美的ASCII码表,毕竟系统什么的都还是人家的。所以GB2312设计时在第一个字节的低位,即ASCII码表中0~127的编号得保留下来,具体的中文字符还得从往后开始排。

    ​ GB2312的出现,基本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆99.75%的使用频率,属于中国国家标准,新加坡地区也可使用此种编码。但对于人名、古汉语等方面出现的罕用字和繁体字不能很好的支持

    GBK

    汉字内码扩展规范

    ​ 聪明的中国人当然很快就意识到了GB2312的不足之处,于是在1995年,又制定了GBK编码,它是16位字符集,即双字节编码,收录有21003个汉字,883个符号,共21886个字符;其主要就是利用了GB2312中还未使用到的区间,继续增添字符,也就是说,其可以完全兼容以前的GB2312。

    GB18030

    信息技术 中文编码字符集

    到了2000年的时候,为了同时能够支持我们国家各种少数名族的语言,国人又推出了新的编码:GB18030

    • 采用变长多字节编码,每个字可以由1个、2个或4个字节组成。
    • 编码空间庞大,最多可定义161万个字符。
    • 它兼容 GB2312,基本兼容 GBK(只有很少几处不同)
    • 完全支持Unicode,无需动用造字区即可支持中国国内少数民族文字、中日韩和繁体汉字以及emoji等字符。

    兼容的代码示例如下:

    String origin = "chackca 与你一起进步";
    String gbk2gb18030 = new String(origin.getBytes("GBK"), "GB18030");
    System.out.println(gbk2gb18030 + ":" + origin.equals(gbk2gb18030));
    //输出:chackca 与你一起进步
    

    ​ 嗯?上面好像说到了Unicode,那么Unicode是个什么东西呢?

    ​ 这里我们来铺垫一个背景:

    ​ 上文我们说了美国制定了Ascii表,用0~127位来表示它们用到的大部分的字符,当时美国制定完这个规则后,首先传入计算机的是欧洲等地区,我们知道欧洲的一些国家语言可不是英文,这个时候,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。由此产生了适用于各个国家的编码方式,也就是上文说的ANSI编码。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使用的编码体系,可以表示最多256个符号。但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0–127表示的符号是一样的,不一样的只是128–255的这一段。

    ​ 在这种情况下,每个国家都出现了不同的编码,我们常见的电子邮件的乱码,就是因为发信人和收信人使用的编码方式不一样。那么如何解决这种情况呢?如果有一种编码方式,能够支持所有国家的字符,让大家都使用,是不是就不会出现这种情况了?

    ​ 在这种情况下,Unicode就应运而生了。

    Unicode

    Unicode(中文:万国码、国际码、统一码、单一码)是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得计算机可以用更为简单的方式来呈现和处理文字。

    ​ Unicode至今仍在不断增修,每个新版本都加入更多新的字符。目前最新的版本为2020年3月公布的13.0.0。

    ​ 需要注意的是,Unicode 只是一个符号集/字符集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。这么做是有一定的考虑的。

    ​ 我们假设,Unicode规定所有字符必须使用4个字节进行存储(因为字符太多,只能用这么多字节才能将所有字符都表示起来),那么原本的Ascii码表的字符,本来可以直接使用1个字节表示的,现在就都得变成使用4个字节,其他字节位置需要补充0,这对于存储来说是极大的浪费。因此,为了解决这个问题,市场上就出现了很多中间格式的字符集,他们被称为通用转换格式,即 UTF(Unicode Transformation Format),而我们常见的有:UTF-7, UTF-7.5, UTF-8,UTF-16, 以及 UTF-32。我们可以说,UTF-8、UTF-16等都是 Unicode 的一种实现方式。

    这里我们对常见的三种进行介绍:

    UTF-8

    • 使用1~4个字节为每个字符编码

    • 当字符在ASCII中可以被表示时,UTF-8编码方式就用一个字节来表示它。

    • 在UTF-8中汉字用3个字符来表示。

    • 自同步编码,在传输过程中如果有字节序列丢失,并不会造成任何乱码现象,或者存在错误的字节序列也不会影响其他字节的正常读取。例如读取了一个 10xxxxxx 开头的字节,但是找不到首字节,就可以将这个后续字节丢弃,因为它没有意义,但是其他的编码方式,这种情况下就很可能读到一个完全不同或者错误的字符。

    UTF-16

    • 使用2~4个字节为每个字符编码

    • 由于UTF-16固定使用两个字节表示一个字符,所以UTF-16不能与ASCII兼容。

    • 在不同的机器中UTF-16存在因存储方式不同(大端法和小端法)导致数据有误,因此存在UTF16-LE和UTF16-BE两种UTF16的变体。

    • 相比较UTF-8,在存储中文方面,UTF16更加节省空间(仅用两个字节存储中文)。

    • UTF-16容错情况比UTF-8好,因为UTF-16大部分情况下稳定使用两个字节编码,如果数据错误不会连代其他数据被读错,而UTF-8是变长编码,可能导致后面的字符全部错误。
      UTF-16广泛应用在各种系统中。

    UTF-32

    • 使用4个字节为每个字符编码

    ​ UTF-32可以说是“真正”的unicode编码,unicode用四个字节表示一个字符的特点在UTF-32中实现了,理论上这样根本不需要复杂的分配字节的方法,只需要每个字符一一对应即可,而且UTF-32的超大容量装得下任何的字符。但是问题也就在这里,一个字符需要四个字节太过于奢侈,因此,UTF-32并不是一个很常用的编码方法。

    ​ 看到这里,你大概就会明白,为什么我们常见的UTF转换格式是UTF-8了吧,因为其使用变长字节来储存 Unicode字符,对于原本的ASCII字母,继续让其使用第一字节的位置存储,也就是可以兼容Ascii表,而对于重音文字、希腊字母或西里尔字母等则使用2字节来储存,而常用的汉字就要使用3字节,辅助平面字符则使用4字节。通过此种方式,UTF-8基本上就可以表示了所有的文字。而如果我们选择了使用UTF-16,则注定了无法直接兼容ASCII。

    ​ 或许你会好奇UTF-8是怎么实现变长字符的,你可以点击下面链接进行了解

    为什么UTF-8比UTF-16更费空间

    或者直接看下面的总结:

    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
    
    在实际的解码过程中:
    情况 1:读取到一个字节的首位为 0,表示这是一个单字节编码的 ASCII 字符;
    情况 2:读取到一个字节的首位为 1,表示这是一个多字节编码的字符,如继续读到 1,则确定这是首字节,在继续读取直到遇到 0 为止,一共读取了几个 1,就表示该字符为几个字节的编码;
    情况 3:当读取到一个字节的首位为 1,紧接着读取到一个 0,则该字节是多字节编码的后续字节。
    

    ​ 通过上面的介绍,我们知道了UTF-8是Unicode的实现,也就代表了它可以支持几乎所有的字符,那么,既然它这么强,为什么还会出现其他的编码格式呢?也就是说它肯定是存在缺点的。

    ​ 而其实,它的优点即是它的缺点

    ​ 对于那些优先纳入UTF-8的字符,它们可以采用1-2个字节便定义了自己的字符,但是对于后来者,由于前面的位置已经被占满了,只能同时使用后面3-4字节的位置,那么它的存储空间就会相对大一些,这就造成了某种“不公平”的现象。

    ​ 而实际上,对于大部分的网站服务器,它们基本都是服务于一个国家或地区的,比如一个中国的网站,一般来说只会出现简体字和繁体字和一些英文字符,很少会出现日语或者韩文、法语等等。

    ​ 而我们知道在UTF-8中,对于中文是采用3字节存储的,如果有一种编码用2个字节即存储了中文,那么对我们的中国的应用将是非常有利的,因此,我们迫切需要一种采用双字节来编码中文的编码格式。因此就出现了上文的GB2312、GBK,然后还有GB18030。

    ​ 等等,GB18030?

    ​ 这里你可能会问:“我记得上文说GB18030是一种变长的多字节编码啊?为什么也放在这里了?”

    ​ 实际上,GB18030也是Unicode的一种实现,我们可以理解为它是一种UTF,只是为了支持原有的GBK映射,所以显得比较反常,它使用的是不同于UTF-8或UTF-16生成的字节序列进行编码。

    ​ 从上面我们可以知道,GB18030是兼容GBK的,且是可变长度的,也就是说使用它的话大部分的中文字符都还是双字节编码的,嗯~还可以接受

    ​ 这里要注意的是,UTF-8中的中文是使用3字节存储的,而我们上文说道的GB2312、GBK等由于是使用双字节存储,所以他们是无法兼容使用的。因此,假设一个外国人要访问你的GBK网页,则ta需要去下载中文语言包支持。而访问UTF-8编码的网页则不会出现这问题,可以直接访问。

    ​ 所以其中的区别就是

    GBK包含全部中文字符;

    UTF-8则包含全世界所有国家需要用到的字符。

    ​ 因此,经常开发网页前端的人可能会遇到这个问题:网页编写UTF-8和GBK哪个编码好?

    这种情况就应该根据个人需要选择了

    1. 如果你主要做中文程序的开发,客户也主要是中国人的话就用GBK吧,因为UTF-8编码的中文使用了三个字节,比GBK的双字节多,所以用GBK可以节省些空间。

    2. 如果是做英文网站开发,那就用UTF-8吧,因为UTF-8中的英文只占一个字节。虽然GBK中的英文也是一个字节的,但是国外客户访问GBK编码的网页有些时候是需要下载语言包的,所以为了用户的方便,还是使用UTF-8吧。

    3. 如果你的网站是中文的,但国外用户也不少,最好也用UTF-8的吧。

    Mysql 之 utf8mb4

    ​ 那么,我们知道了基本的UTF格式,但是你肯定见过在mysql大行其道的utf8mb4,正如文章开头的数据库错乱例子,为什么别人给了你一份数据库数据,说是utf-8格式的,你按照它说的格式创建了,导入数据后却还出现了乱码?

    在这里插入图片描述

    ​ 实际上,MySQL是 从 4.1 版本开始支持 UTF-8,也就是 2003 年,那时mysql还是很不错的,知道业内有这个编码格式,而且使用的人还挺多,便快速地跟上时代发展的步伐,给用户支持了UTF-8的编码格式,那会的UTF-8规定使用一至六个字节为每个字符编码。而Mysql 中的 utf8 定义了支持最长3个字节。

    ​ 至于为什么人家UTF-8要求1-6个字节,而mysql只支持1-3个字节,业界也都是猜测,大家也可以看下面这篇文章

    ​ 殊不知,刚刚好在它支持UTF-8的那一年,也就是2003年11月,UTF-8便被RFC 3629重新规范,要求最多支持的字节变成了四个。后来,新的UTF-8格式被越来越多的人接受,使用者也越来越多。

    ​ World的天,正因为如此,导致mysql在utf-8的定义上被挖了个大坑,你说吧,用户都已经接入了,数据都已经存进来了,这可是万万不能动的,况且,互联网中软件的更新可都是提倡向上兼容的,Mysql总不能把这utf-8的编码格式给直接删了吧

    ​ 因此MySQL只好妥协了,它在5.5.3(2010年)之后增加了这个utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode。好在utf8mb4是utf8的超集(4字节>3字节),除了将编码改为utf8mb4外不需要做其他转换。当然,如果你为了节省空间,一般情况下使用utf8也就够了。(这里大家也可以想一下,为什么mysql不直接在新版本把原来的utf8改成支持1-4字节的)

    ​ 嗯?节省空间?不是说了UTF-8是变长的嘛?那么我平时存储3字节的字符,在utf8和utf8mb4应该都是一样的啊,怎么会节省呢?

    ​ 其实,在mysql上,对于 CHAR 类型数据,utf8mb4 会多消耗一些空间,所以,根据 Mysql 的官方建议,使用 VARCHAR 替代 CHAR。

    ​ 存储时,CHAR不管实际存储数据的长度,直接按照CHAR规定的长度分配存储空间;而后者会根据实际存储的数据分配最终的存储空间。所以通常情况下,varchar能够节约磁盘空间。

    char(n) 无论存储了多少个字符,实际所占存储长度都为n
    varchar(n) 占用存储长度仅取决于你实际存放了几个字符
    上面的n表示n个字符,无论汉字和英文,Mysql都能存入n个字符,仅是实际字节长度有所区别

    正因为char类型的字符数是从定义下来的时候就固定的,所以,MySQL必须事先为它准备好相应的存储空间。

    比如为 utf8mb4字符集的char类型的列每一个字符保留四字节的空间,因为其最大长度可能是四字节。
    而为 utf8字符集的列的每一个字符则仅需保留三字节的空间,因为其最大长度只可能是三个字节。
    例如,MySQL必须为一个使用 utf8mb4 字符集的 char(10)的列保留40字节空间。

    ​ 好了我们回来,其实,一般情况下,如果你选了utf8来存储你的中文信息也是不会有问题的,但是当你遇到了一些比较新鲜的字符,或者一些不常见的汉字,任何新增的 Unicode 字符,就会发生插库异常,这个时候你就得考虑把数据库编码换成utf8mb4了

    在这里插入图片描述

    ​ 在这里也建议大家,以后在选择数据库编码的时候,如果是要使用utf-8这个编码,则直接选择utf8mb4吧,防止未来出现任何不可控力导致乱码或者插库异常问题。

    乱码(锟斤拷)是怎样炼成的

    ​ 讲了这么多,那么接下来回到我们文章开头提到的乱码问题吧:

    在这里插入图片描述

    ​ 相信你可能曾经也在某乎上搜索过以上相似的内容,虽然结果和我的不太一样,这本书是我小时候的启蒙书,它对我的编程习惯影响至今,使我练就了钢铁般的编码意识,奥斯勒洛夫斯基就是我为数不多的男神…之一。🐶

    ​ 以至于谈到如何炼成一份乱码,我就手到擒来:

    public static void main(String[] args) { 
        String origin = "chackca 与你一起进步";
        System.out.println("GB2312编码,GB2312解码:" + new String(origin.getBytes("GB2312"), "GB2312"));
        System.out.println("GB2312编码,GBK解码:" + new String(origin.getBytes("GB2312"), "GBK"));
        System.out.println("GB2312编码,GB18030解码:" + new String(origin.getBytes("GB2312"), "GB18030"));
        System.out.println("GB2312编码,UTF-8解码:" + new String(origin.getBytes("GB2312"), "UTF-8"));
        System.out.println("GBK编码,UTF-8解码:" + new String(origin.getBytes("GBK"), "UTF-8"));
    }
    

    输出结果

    GB2312编码,GB2312解码:chackca 与你一起进步
    GB2312编码,GBK解码:chackca 与你一起进步
    GB2312编码,GB18030解码:chackca 与你一起进步
    GB2312编码,UTF-8解码:chackca ����һ�����
    GBK编码,UTF-8解码:chackca ����һ�����
    

    ​ 如上,一份热腾腾的乱码就出来了

    ​ 其中,前三行由于我们上文说了GB2312、GBK、GB18030之间的兼容性问题,所以我们不会看到乱码,而后面,由于GB2312编码的字符集和UTF-8解码的字符集不一致,才会导致了乱码的问题

    ​ 那么锟斤拷是如何产生的呢?

    ​ 在Unicode和老编码体系的转化过程中,肯定会有一些字,是用Unicode是没法表示的,而这个时候,Unicode官方用了一个占位符来表示这些文字,这个字符就是 � ,他也是Unicode中定义的一个特殊字符,所有无法表示的字符都会通过这个字符来表示。这就是:U+FFFD REPLACEMENT CHARACTER。

    在这里插入图片描述

    在Unicode官方文档中,它的10进制表示是65533,当我们使用UTF-8编码时,那么他的16进制形式就是

    String origin = "�";
    System.out.println(bytesToHex(origin.getBytes("UTF-8")));
    

    输出:

    0xEF 0xBF 0xBD (三个字节)
    

    这里可能你会有点疑惑,因为65533,用二进制转16进制,转出来的是FFFD,但是UTF-8(16进制)却是:0xEF 0xBF 0xBD,其实这里面正是应用了上文提到的UTF-8为了兼容1字节存储而使用的变换二进制变换手法,如下:

    65533  				->  11111111	11111101       			//十进制转二进制
    11111111 11111101   ->  11101111	10111111	10111101	//普通二进制转UTF-8二进制存储
    					->  ef 			bf 			 bd			//转换为相应的hex(3个byte)
    

    转换过程如上,那么我们继续下去

    如果刚刚好出现两个连续的字符都无法显示,那么其就是

    0xEF 0xBF 0xBD 0xEF 0xBF 0xBD
    

    这个时候,按照我们中文的编码格式GBK来解码的话,因为GBK中一个汉字占用两个字节,那么就可以归类为:

    0xEF 0xBF, 0xBD 0xEF, 0xBF 0xBD   ---->  即: 0xEFBF	0xBDEF	0xBFBD
    

    那么,等GBK展示给用户,就是锟(0xEFBF),斤(0xBDEF),拷(0xBFBD)

    String origin = "��";
    System.out.println("GBK编码,UTF-8解码:" + new String(origin.getBytes("UTF-8"), "GBK"));
    
    String str = "激极尽致,求真品诚";
    String gbk2UtfString = new String(str.getBytes("GBK"), "UTF-8");
    System.out.println("GBK转换成UTF-8:" + gbk2UtfString);
    
    String gbk2Utf2GbkString = new String(gbk2UtfString.getBytes("UTF-8"), "GBK");
    System.out.println("GBK转换成UTF-8再转成GBK:" + gbk2Utf2GbkString);
    

    输出:

    GBK编码,UTF-8解码:锟斤拷
    GBK转换成UTF-8:�������£�����Ʒ��
    GBK转换成UTF-8再转成GBK:锟斤拷锟斤拷锟斤拷锟铰o拷锟斤拷锟斤拷品锟斤拷
    

    以上,我们可以知道,以后如果再见到锟斤拷,肯定是UTF-8和GBK的转换问题。

    扩展阅读:
    https://mp.weixin.qq.com/s/C3iazvqdI8lfxBcr7GbwiA

    展开全文
  • 字符集和字符编码

    2020-03-27 11:32:43
    现在的编程语言对字符串的处理一般封装比较好,所以平时编写代码,很少要自己考虑字符编码问题。以前学习xml时,由于xml的存储涉及到编码格式,查过一些资料,知道一些概念,GB2312、Unicode、Utf-8、Utf-16、UCS-2...
  •  而字符编码是为方便对每个字符信息一个集合体,以便于编程人员的对字符显示后期处理。为了方便在不同平台的信息传递的准确性,所以产生统一字符编码的规范编码。字符编码简介(信息来至百度百科)...
  • 二进制与字符编码

    2016-08-21 21:06:00
    大五码是一种繁体中文汉字字符集,其中繁体汉字13053个,808个标点符号、希腊字母及特殊符号。大五码的编码码表直接针对存储而设计,每个字符统一使用两个字节存储表示。第1字节范围81H-FEH,避开了同ASCII码的冲突...
  • 喾哲~ (八月最佳)

    千次阅读 多人点赞 2019-08-21 18:12:10
    《目录》 数学的起源 贝叶斯概率:如何漂白王境泽的真相定律 ? 傅立叶变换:您写的文章真的是 原创 吗 ? 哈夫曼编码:如何创造一门数字语言 ? 最大熵原理:我知道我会在哪里死,又如何?...
  • utf-8 我们的汉字至少有上千个字符,GB-2312(即GBK)编码在ASCII的基础上增加了汉字、增加了汉语标点符号、增加了全角英文字符(ASCII里面的半角英文字符ABC才是标准的正统,全角ABC是盗版的)、没有增加日语等...
  • 标准中文电码查询;BMI计算;区号查询;简繁体转换 三、文体娱乐 博客 Blogger - Blogger API v3 版本允许你创建新的博客, 编辑或者删除已经存在的博客, 查询符合特定标准的博客. Medium - 访问 medium.com 的...
  • 开发者API资源(接口整理)

    万次阅读 多人点赞 2018-11-14 10:17:56
    标准中文电码查询 ; BMI计算 ; 区号查询 ; 简繁体转换 三、文体娱乐 博客 Blogger  - Blogger API v3 版本允许你创建新的博客, 编辑或者删除已经存在的博客, 查询符合特定标准的博客.  Medium  -...
  • 手电筒开和关的时间长度并没有限定,这取决于点的时间长度,点长又由手电筒开关触发的速度和摩尔斯电码发送者记忆电码的熟练程度来决定,熟练发送者的划也许与生手的点等长。这个小问题会使接收电码有些困难,但在一...
  • API大全 汇总(转载)

    万次阅读 2019-01-11 11:54:25
    标准中文电码查询 ; BMI计算 ; 区号查询 ; 简繁体转换 三、文体娱乐 博客 Blogger  - Blogger API v3 版本允许你创建新的博客, 编辑或者删除已经存在的博客, 查询符合特定标准的博客. Medium  - ...
  • API汇总;API大全(转载)

    千次阅读 2019-01-11 19:59:01
    标准中文电码查询;BMI计算;区号查询;简繁体转换 三、文体娱乐 博客 Blogger - Blogger API v3 版本允许你创建新的博客, 编辑或者删除已经存在的博客, 查询符合特定标准的博客. Medium - 访问 medium.com...
  • )对比汉语,TEX的发音近似于“泰赫”,而且可以用汉语拼音准确地拼出来:têh(或许老一辈的人习惯用注音:ㄊㄝㄏ)。 LATEX这个名字则是把LATEX之父Lamport博士[3]的姓和TEX混合得到的。所以LATEX大约应该读成“拉...
  • 国内外API总结

    千次阅读 2019-06-16 23:32:08
    标准中文电码查询 ; BMI计算 ; 区号查询 ; 简繁体转换 三、文体娱乐 博客 Blogger - Blogger API v3 版本允许你创建新的博客, 编辑或者删除已经存在的博客, 查询符合特定标准的博客. Medium - 访问 ...
  • 常用API大全汇总

    千次阅读 多人点赞 2019-12-26 14:53:41
    标准中文电码查询;BMI计算;区号查询;简繁体转换 三、文体娱乐 博客 Blogger - Blogger API v3 版本允许你创建新的博客, 编辑或者删除已经存在的博客, 查询符合特定标准的博客. Medium - 访问 medium.com 的...
  • MIT(计算机科学) 学习心得

    千次阅读 2019-01-10 13:57:09
    电报最早是由美国的摩尔斯在1844年发明的,故也被叫做摩尔斯电码。它由两种基本信号和不同的间隔时间组成:短促的点信号" .",读" 的 “(Di);保持一定时间的长信号”—",读"答 "(Da)。间隔时间:滴,1t;答,...
  • 【史上最全】国内外常用精品API接口汇总

    万次阅读 多人点赞 2018-11-12 15:27:53
    标准中文电码查询 ; BMI计算 ; 区号查询 ; 简繁体转换 三、文体娱乐 博客 Blogger  - Blogger API v3 版本允许你创建新的博客, 编辑或者删除已经存在的博客, 查询符合特定标准的博客. Medium  - ...
  • 文章目录 一、信息与冗余 二、香农的洞见 三、信息熵计算公式 四、编程计算信息熵 (一)编程计算上文涉及的信息熵 (二)编写Python函数计算字符串的信息熵 1、编写程序“计算字符串的信息熵.py” 2、运行程序,...
  • 前后端技术科普

    千次阅读 2019-08-24 20:59:18
    打个比方,清朝的皇帝不懂汉语(别当真),要看懂汉臣们写的奏折,就要雇一个翻译官。翻译官的工作就是,一条条的读取奏折里的内容,翻译成满语,然后一条条呈递给皇帝。 这个例子里,奏折是我们写的JAVA 代码,...
  • 标准中文电码查询;BMI计算;区号查询;简繁体转换 三、文体娱乐 博客 Blogger - Blogger API v3 版本允许你创建新的博客, 编辑或者删除已经存在的博客, 查询符合特定标准的博客. Medium - 访问 medium.com 的...
  • 有很多新科技,如可扩展置标语言(Extensible Markup Language,简称:XML)、Java编程语言以及现代的操作系统,都采用Unicode编码。 utf UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度...

空空如也

空空如也

1 2
收藏数 27
精华内容 10
关键字:

中文代码汉语编程