当前位置: 移动技术网 > IT编程>脚本编程>Go语言 > Go语言中多字节字符的处理方法详解

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

2018年11月08日  | 移动技术网IT编程  | 我要评论

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

完!

总结

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网