ο 不是o,开发中希腊字母捣什么乱?探明字符串string转为字节数组后,字节数组内元素的含义

一、背景&经历

今天帮女朋友看一段html代码:

<html>
<head>
head>
<body>
<div>用户名:
    <input type="text" id="name" >
    <br><button οnclick="test()">提交button>
div>
<script>
	function test(){

	var str=document.getElementById("name").value;
	if(str==""){
		alert("若没有输入用户名,请输入用户名");
	}
}
script>
body>
html>

希望实现的是点击按钮,能弹出一个提示框,但是就是不合适。
实在不知道是什么地方出现了问题。

copy到idea中,我无意中看到的了onclick的颜色有点黄,鼠标悬浮上去,显示:
ο 不是o,开发中希腊字母捣什么乱?探明字符串string转为字节数组后,字节数组内元素的含义_第1张图片
完全看不出有啥区别,但是点击之后,就没有黄底了,而且代码也合适了。
我试着用代码解释下这个区别:

package main

import "fmt"

func main() {
	s1 := "οnclick"
	s2 := "onclick"

	fmt.Println(s1 == s2)
	fmt.Println([]byte(s1))
	fmt.Println([]byte(s2))

}

结果如下:

false
[206 191 110 99 108 105 99 107]
[111 110 99 108 105 99 107]

Process finished with exit code 0

了解了,第一个字符并不是英文字母o,是个特殊字符。。。。。
unicode 编码,GREEK SMALL LETTER OMICRON,希腊小写字母OMICRON,unicode=959,而英文字母o为111. 这个网站列出来了所有的unicode字符和其编码,https://www.ssec.wisc.edu/~tomw/java/unicode.html
在这里插入图片描述

二、各种编程语言中,string和字节数组byte[]中是如何转化的?

可以看出,这个希腊字母是个双字节字符,计算机中,一个字节为8bit,在各个编程语言中,都有不同的数据类型正好为8bit,golang中的byte实际是uint8,无符号8bit的整型类型(范围0~255)。在Java中,byte为有符号的8bit整型(范围-128~127)。

package main

import "fmt"

func main() {
	
	fmt.Println('ο')
	fmt.Println([]byte("ο"))

}

显示结果:

959
[206 191]

Process finished with exit code 0

为什么这个unicode为959的字符转化为byte数组是[206 ,191]呢??

这就牵扯到了unicode的编码规则:

1、对于单字节的符号,字节的第一位(字节的最高位)设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
2、对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

下表总结了编码规则,字母x表示可用编码的位 :

Unicode符号范围 UTF-8编码方式 字节数
0000 0000-0000 007F [0-127] 0xxxxxxx 1
0000 0080-0000 07FF [128-2047] 110xxxxx 10xxxxxx 2
0000 0800-0000 FFFF [2048-65535] 1110xxxx 10xxxxxx 10xxxxxx 3
0001 0000-0010 FFFF [65536-1114111] 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 4

string到byte[]转化的过程是这样的:

  1. 逐个字符的遍历
  2. 遍历到某个字符时,确定字符的unicode编码,还是以这个希腊字母ο为例(unicode=959)
    959的二进制为:11 1011 1111 16进制为: 3BF
  3. 因为959处于0000 0080-0000 07FF
    [128-2047]中,所以为2字节字符,对应的byte数组长度就是2。所以编码格式为:110xxxxx 10xxxxxx
  4. 由低位到高位按照959二进制的低位到高位依次填充,若长度不足用0补充,得到:
    [11001110]、[10111111],对应的10进制就是[206]、[191]

从byte[]到string的转化过程如下(以[229 188 160 51]为例):

  1. 以二进制方式解析第一个byte元素229,其补码为:11100101

  2. 二进制序列从前向后看,第一个0之前有3个1,说明正在解析一个三字节字符,所以编码格式为1110xxxx 10xxxxxx
    10xxxxxx

  3. 因为是3字节字符,所以后面两个byte元素仍一起来表示同一个字符。

     229 -> 1110`0101`
     188 -> 10`111100`
     160 -> 10`100000`
    
  4. 所以实际的uncode为:0101 111100 100000 ,即 24352 ,就是汉字""

  5. 继续按照上述流程循环byte数组,得到51,易知为数字“3”

至此,解析完毕 ,字符串为:“张3”.

最后,值得一提的是,各种编程语言的byte含义不完全一样,但是都是按照二进制补码进行解析的,实际的值不一样,但是对应的补码是一致

在Java中,οnclick的byte数组为 [-50, -65, 110, 99, 108, 105, 99, 107]
Java中byte为带符号的8bit整型,首位为符号位,-50补码为:11001110
Golang中byte为无符号的8bit整型中,无符号位,206补码为:11001110

两者是一致的!

你可能感兴趣的:(java,Golang,学习)