Unicode码


字符有英文 中文 韩文等  需要映射表把世界上的字符映射成计算机可阅读的二进制数字(字节)
每个字符都给个独一无二的编码 避免出现写文字的人和阅读文字的人 因编码不同而出现无法读取的乱码现象
Unicode  是所有符号的编码映射
最开始 unicode 使用两个字节  就是16位就能包含所有的字符
但是 两个字节最多只能覆盖65536个字符不够
于是附加了一套字符编码 即unicode 4.0
附加的字符用4个字节表示 大概Unicode可以覆盖100多万个字符了
Unicode只是定义了一个字符和一个编码的映射 对应的存储没有制定
如一个编码0x0041代表大写字母A 那么可能有一种存储至少有4个字节 那可能0x00000041来存储代表A
这个就是 unicode 的具体实现
unicode具体实现有很多种 UTF-8 和 UTF-16 就是其中两种
UTF-8 最少用一个字节就能表示一个字符的编码实现
采取的方式是对不同的语言使用不同的方法 将unicode编码按照这个方法进行转换
只要记住最后的结果是
英文占一个字节
中文占三个字节
这种编码实现方式 是应用最为广泛的方式了
UTF-16 最少用 两个字节能表示一个字符的编码实现
同样是对unicode编码进行转换 它的结果是英文占用两个字节 中文占用两个或者四个字节
实际上 UTF-16 就是最严格实现了 unicode4.0
但由于英文是最通用的语言 所以推广程度没有 UTF-8 那么普及

go对unicode包的支持

由于 UTF-8 的作者 Ken Thompson 是go语言的创始人
在字符支持方面 几乎没有语言的理解会高于go了
go对 unicode 的支持包含三个包
unicode
unicode/utf8
unicode/utf16
unicode包包含基本的字符判断函数
utf8包主要负责 rune 和 byte 之间 转换
utf16包负责 rune 和 uint16 数组之间的转换
由于字符的概念有的时候比较模糊
比如字符(小写a)普通显示为a 在重音字符中(grave-accented)中显示为à
这时候字符(character)的概念就有点不准确了
因为a和à显然是两个不同的unicode编码
但是却代表同一个字符
所以引入了rune  一个rune代表一个unicode编码
所以上面的a和à是两个不同的rune
go语言的所有代码都是UTF8的
所以 程序中的字符串 都是utf8编码的 但是单个字符(单引号扩起来的)却是 unicode 的

unicode包

unicode包含了对rune的判断
把所有 unicode 涉及到的编码进行了分类 使用结构
type RangeTable struct {
R16         []Range16
R32         []Range32
LatinOffset int
}
表示这个功能的字符集 这些字符集都集中列表在 table.go 这个源码里面
如控制字符集
var _Pc = &RangeTable{
R16: []Range16{
  {0x005f, 0x203f, 8160},
  {0x2040, 0x2054, 20},
  {0xfe33, 0xfe34, 1},
  {0xfe4d, 0xfe4f, 1},
  {0xff3f, 0xff3f, 1},
},
}
包的函数 有判断函数
func IsControl(r rune) bool  // 是否控制字符
func IsDigit(r rune) bool  // 是否阿拉伯数字字符 即1-9
func IsGraphic(r rune) bool // 是否图形字符
func IsLetter(r rune) bool // 是否字母
func IsLower(r rune) bool // 是否小写字符
func IsMark(r rune) bool // 是否符号字符
func IsNumber(r rune) bool // 是否数字字符 比如 罗马数字 Ⅷ 也是数字字符
func IsOneOf(ranges []*RangeTable, r rune) bool // 是否是RangeTable中的一个
func IsPrint(r rune) bool // 是否可打印字符
func IsPunct(r rune) bool // 是否标点符号
func IsSpace(r rune) bool // 是否空格
func IsSymbol(r rune) bool // 是否符号字符
func IsTitle(r rune) bool // 是否 title case
func IsUpper(r rune) bool // 是否大写字符
例子
func main() {
single := '\u0015'
fmt.Println(unicode.IsControl(single))  //true
single = '\ufe35'
fmt.Println(unicode.IsControl(single)) // false
digit := rune('1')
fmt.Println(unicode.IsDigit(digit)) //true
fmt.Println(unicode.IsNumber(digit)) //true
letter := rune('Ⅷ')
fmt.Println(unicode.IsDigit(letter)) //false
fmt.Println(unicode.IsNumber(letter)) //true
}

utf8包

utf8里面的函数 有一些字节和字符的转换
判断是否符合utf8编码的函数
func Valid(p []byte) bool
func ValidRune(r rune) bool
func ValidString(s string) bool
判断 rune 的长度的函数
func RuneLen(r rune) int
判断字节串或者字符串的rune数
func RuneCount(p []byte) int
func RuneCountInString(s string) (n int)
编码和解码rune到byte
func DecodeRune(p []byte) (r rune, size int)
func EncodeRune(p []byte, r rune) int

utf16包

utf16的包的函数比较少
将int16和rune进行转换
func Decode(s []uint16) []rune
func Encode(s []rune) []uint16
unicode 有个基本字符平面和增补平面的概念
基本字符平面只有 65535 个字符 增补平面(有16个)加上去就能表示1114112个字符
utf16就是严格实现了unicode的这种编码规范
而基本字符和增补平面字符就是一个代理对(Surrogate Pair) 一个代理对可以和一个rune进行转换
func DecodeRune(r1, r2 rune) rune
func EncodeRune(r rune) (r1, r2 rune)

Go判断字符是汉字


func IsChineseChar(str string) bool {
    for _, r := range str {
        if unicode.Is(unicode.Scripts["Han"], r) {
            return true
        }
    }
    return false
}
func IsChineseCharAll(str string) bool {
    for _, r := range str {
            if unicode.Is(unicode.Scripts["Han"], r) || (regexp.MustCompile("[\u3002\uff1b\uff0c\uff1a\u201c\u201d\uff08\uff09\u3001\uff1f\u300a\u300b]").MatchString(string(r))) {
                    return true
            }
    }
    return false
}

Go 语言 Unicode码点和unicode相关