欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Go语言中多字节字符的处理方法详解

程序员文章站 2022-06-03 08:46:36
1 概述 go语言的字符串是使用 utf-8 编码的。utf-8 是 unicode 的实现方式之一。本文内容包括:utf-8 和 unicode 的关系,go语言提...

1 概述

go语言的字符串是使用 utf-8 编码的。utf-8 是 unicode 的实现方式之一。本文内容包括:utf-8 和 unicode 的关系,go语言提供的 unicode 包和 unicode/utf8 包的使用。

下面话不多说了,来一起看看详细的介绍吧

2 utf-8 和 unicode 的关系

unicode一种字符集,是国际标谁化组织(iso)设计的一个包括了地球上所有文化、所有字母和符号 的编码。他们叫它 universal multiple-octet coded character set,简称 ucs,也就是 unicode。unicode 为每一个 字符 分配一个唯一的 码点(code point),就是一个唯一的值。例如 康 的码点就是 24247,十六进制为 5eb7。

unicode 字符集仅仅定义了字符与码点的对应关系,但是并没有定义该如何编码(存储)这个码值,这就导致了很多问题。例如由于字符的码值不同,导致所需要的存储空间是不一致的,计算机不能确定接下来的字符是占用几个字节。还有就是如果采用固定的长度假设都是4个字节来存储码点值,那么会导致空间的额外浪费,因为 ascii 码字符其实仅仅需要一个字节的空间。

utf-8 就是解决如何为 unicode 编码而设计的一种编码规则。可以说 utf-8 是 unicode 的实现方式之一。其特点是一种变长编码,使用1到4个字节表示一个字符,根据不同的符号而变化长度。utf-8 的编码规则有二:

  • 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 unicode 码。因此对于ascii码字符,utf-8 编码和 ascii 码是相同的。
  • 对于 n 字节的符号(n > 1,2到4),第一个字节的前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
---------------------------------------------------------

go语言中,对于 unicode 和 utf-8 使用了 unicode 和 unicode/utf8 包来实现,下面是阅读 api 的总结和说明。

3 unicode 包

go语言中,提供了 unicode 包,处理与 unicode 相关的操作,整理如下:

is(rangetab *rangetable, r rune) bool

检测 rune r 是否在 rangetable 指定的字符范围内。

rangetable 一个 unicode 码值集合,通常使用 unicode 包中定义的集合。

判断字符是否出现在汉字集合中:

unicode.is(unicode.scripts["han"], 'k')
// 返回 false
unicode.is(unicode.scripts["han"], '康')
// 返回 true

in(r rune, ranges …*rangetable) bool

检测 rune r 是否在多个 rangetable 指定的字符范围内。

rangetable 一个 unicode 码值集合,通常使用 unicode 包中定义的集合。

unicode.in('康', unicode.scripts["han"], unicode.scripts["latin"])
// 返回 true
unicode.in('k', unicode.scripts["han"], unicode.scripts["latin"])
// 返回 true

isoneof(ranges []*rangetable, r rune) bool

检测 rune r 是否在 rangetable ranges 指定的字符范围内。与 in 功能类似,推荐使用 in。

isspace(r rune) bool

检测字符 rune r 是否是空白字符。在latin-1字符空间中,空白字符为:

'\t', '\n', '\v', '\f', '\r', ' ', u+0085 (nel), u+00a0 (nbsp)

其它的空白字符请参见策略z和属性pattern_white_space。

isdigit(r rune) bool

检测字符 rune r 是否是十进制数字字符。

unicode.isdigit('9')
// 返回 true
unicode.isdigit('k')
// 返回 false

isnumber(r rune) bool

检测字符 rune r 是否是 unicode 数字字符。

isletter(r rune) bool

检测一个字符 rune r 是否是字母

unicode.isletter('9')
// 返回 false
unicode.isletter('k')
// 返回 true

isgraphic(r rune) bool

一个字符 rune r 是否是 unicode 图形字符。图形字符包括字母、标记、数字、符号、标点、空白。

unicode.isgraphic('9')
// 返回 true
unicode.isgraphic(',')
// 返回 true

iscontrol(r rune) bool

检测一个字符 rune r 是否是 unicode 控制字符。

ismark(r rune) bool

检测一个字符 rune r 是否是标记字符。

isprint(r rune) bool

检测一个字符 rune r 是否是的可打印字符,基本与图形字符一致,除ascii空白字符u+0020。

ispunct(r rune) bool

检测一个字符 rune r 是否是 unicode标点字符。

unicode.ispunct('9')
// 返回 false
unicode.ispunct(',')
// 返回 true

issymbol(r rune) bool

检测一个字符 rune r 是否是 unicode 符号字符。

islower(r rune) bool

检测一个字符 rune r 是否是小写字母。

unicode.islower('h')
// 返回 true
unicode.islower('h')
// 返回 false

isupper(r rune) bool

检测一个字符 rune r 是否是大写字母。

unicode.isupper('h')
// 返回 false
unicode.isupper('h')
// 返回 true

istitle(r rune) bool

检测一个字符 rune r 是否是title字符。大部分字符的 title 格式就是其大写格式,少数字符的 title 格式是特殊字符,例如 ᾏᾟᾯ。

unicode.istitle('ᾯ')
// 返回 true
unicode.istitle('h')
// 返回 false
unicode.istitle('h')
// 返回 true

to(_case int, r rune) rune

将字符 rune r 转换为指定的格式,格式_case支持:unicode.uppercase、unicode.lowercase、unicode.titlecase

unicode.to(unicode.uppercase, 'h')
// 返回 h

tolower(r rune) rune

将字符 rune r 转换为小写。

unicode.tolower('h')
// 返回 h

func (specialcase) tolower

将字符 rune r 转换为小写。优先使用映射表 specialcase。

映射表 specialcase 是特定语言环境下大小写的映射表。主要应用于一些欧洲字符,例如土耳其 turkishcase。

unicode.turkishcase.tolower('İ')
// 返回 i

toupper(r rune) rune

将字符 rune r 转换为大写。

unicode.toupper('h')
// 返回 h

func (specialcase) toupper

将字符 rune r 转换为大写。优先使用映射表 specialcase。

映射表 specialcase 是特定语言环境下大小写的映射表。主要应用于一些欧洲字符,例如土耳其 turkishcase。

unicode.turkishcase.toupper('i')
// 返回 İ

totitle(r rune) rune

将字符 rune r 转换为 title 字符。

unicode.totitle('h')
// 返回 h

func (specialcase) totitle

将字符 rune r 转换为 title 字符。优先使用映射表 specialcase。

映射表 specialcase 是特定语言环境下大小写的映射表。主要应用于一些欧洲字符,例如土耳其 turkishcase。

unicode.turkishcase.totitle('i')
// 返回 İ

simplefold(r rune) rune

在 unicode 标准字符映射中查找与 rune r 互相对应的 unicode 码值。向码值大的方向循环查找。互相对应指的是同一个字符可能出现的多种写法。

unicode.simplefold('h')
// 返回 h
unicode.simplefold('φ')) 
// 返回 φ

4 unicode/utf8 包

decodelastrune(p []byte) (r rune, size int)

解码 []byte p 中最后一个 utf-8 编码序列,返回该码值和长度。

utf8.decodelastrune([]byte("小韩说课"))
// 返回 35838 3
// 35838 就是课的 unicode 码值

decodelastruneinstring(s string) (r rune, size int)

解码 string s 中最后一个 utf-8 编码序列,返回该码值和长度。

utf8.decodelastruneinstring("小韩说课")
// 返回 35838 3
// 35838 就是课的 unicode 码值

decoderune(p []byte) (r rune, size int)

解码 []byte p 中第一个 utf-8 编码序列,返回该码值和长度。

utf8.decoderune([]byte("小韩说课"))
// 返回 23567 3
// 23567 就是 小 的 unicode 码值

decoderuneinstring(s string) (r rune, size int)

解码 string s 中第一个 utf-8 编码序列,返回该码值和长度。

utf8.decoderuneinstring("小韩说课")
// 返回 23567 3
// 23567 就是 小 的 unicode 码值

encoderune(p []byte, r rune) int

将 rune r 的 utf-8 编码序列写入 []byte p,并返回写入的字节数。p 满足足够的长度。

buf := make([]byte, 3)
n := utf8.encoderune(buf, '康')
fmt.println(buf, n)
// 输出 [229 186 183] 3

fullrune(p []byte) bool

检测 []byte p 是否包含一个完整 utf-8 编码。

buf := []byte{229, 186, 183} // 康
utf8.fullrune(buf)
// 返回 true
utf8.fullrune(buf[:2])
// 返回 false

fullruneinstring(s string) bool

检测 string s 是否包含一个完整 utf-8 编码。

buf := "康" // 康
utf8.fullruneinstring(buf)
// 返回 true
utf8.fullruneinstring(buf[:2])
// 返回 false

runecount(p []byte) int

返回 []byte p 中的 utf-8 编码的码值的个数。

buf := []byte("小韩说课")
len(buf)
// 返回 12
utf8.runecount(buf)
// 返回 4

runecountinstring(s string) (n int)

返回 string s 中的 utf-8 编码的码值的个数。

buf := "小韩说课"
len(buf)
// 返回 12
utf8.runecountinstring(buf)
// 返回 4

runelen(r rune) int

返回 rune r 编码后的字节数。

utf8.runelen('康')
// 返回 3
utf8.runelen('h')
// 返回 1

runestart(b byte) bool

检测字节 byte b 是否可以作为某个 rune 编码的第一个字节。

buf := "小韩说课"
utf8.runestart(buf[0])
// 返回 true
utf8.runestart(buf[1])
// 返回 false
utf8.runestart(buf[3])
// 返回 true

valid(p []byte) bool

检测切片 []byte p 是否包含完整且合法的 utf-8 编码序列。

valid := []byte("小韩说课")
invalid := []byte{0xff, 0xfe, 0xfd}
utf8.valid(valid)
// 返回 true
utf8.valid(invalid)
// 返回 false

validrune(r rune) bool

检测字符 rune r 是否包含完整且合法的 utf-8 编码序列。

valid := 'a'
invalid := rune(0xfffffff)
fmt.println(utf8.validrune(valid))
// 返回 true
fmt.println(utf8.validrune(invalid))
// 返回 false

validstring(s string) bool

检测字符串 string s 是否包含完整且合法的 utf-8 编码序列。

valid := "小韩说课"
invalid := string([]byte{0xff, 0xfe, 0xfd})
fmt.println(utf8.validstring(valid))
// 返回 true
fmt.println(utf8.validstring(invalid))
// 返回 false

完!

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。