1 概述

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

2 UTF-8Unicode 的关系

Unicode一种字符集,是国际标谁化组织(ISO)设计的一个包括了地球上所有文化、所有字母和符号 的编码。他们叫它 Universal Multiple-Octet Coded Character Set,简称 UCS,也就是 UnicodeUnicode 为每一个 字符 分配一个唯一的 码点(Code Point),就是一个唯一的值。例如 康 的码点就是 24247,十六进制为 5eb7
Unicode 字符集仅仅定义了字符与码点的对应关系,但是并没有定义该如何编码(存储)这个码值,这就导致了很多问题。例如由于字符的码值不同,导致所需要的存储空间是不一致的,计算机不能确定接下来的字符是占用几个字节。还有就是如果采用固定的长度假设都是4个字节来存储码点值,那么会导致空间的额外浪费,因为 ascii 码字符其实仅仅需要一个字节的空间。

UTF-8 就是解决如何为 Unicode 编码而设计的一种编码规则。可以说 UTF-8Unicode 的实现方式之一。其特点是一种变长编码,使用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 使用了 unicodeunicode/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

完!
原文出自:小韩说课
微信关注:小韩说课

Go语言中多字节字符的处理的更多相关文章

  1. R语言中的字符处理

    R语言中的字符处理 (2011-07-10 22:29:48) 转载▼ 标签: r语言 字符处理 字符串 连接 分割 分类: R R的字符串处理能力还是很强大的,具体有base包的几个函数和strin ...

  2. c语言中的字符数组与字符串

    1.字符数组的定义与初始化 字符数组的初始化,最容易理解的方式就是逐个字符赋给数组中各元素. char str[10]={ 'I',' ','a','m',' ',‘h’,'a','p','p','y ...

  3. VC++中多字节字符集和Unicode之间的互换

    在Visual C++.NET中,默认的字符集是Unicode,这和Windows默认的字符集是一致的,不过在老的VC6.0等工程中,默认的字符集形式是多字节字符集(MBCS:Multi-Byte C ...

  4. C语言中的字符和字符串

    C语言在中常常出现字符和字符串,而一串字符或者字符串其实就是数组 字符数组的定义 char arr[]={'h','e','l','l','o','\0'}; 而定义字符串: char arr1[]= ...

  5. [日常] C语言中的字符数组和字符串

    c语言字符数组和字符串:1.存放字符的数组称为字符数组 char str[]2.'\0'也被称为字符串结束标志3.由" "包围的字符串会自动在末尾添加'\0'4.逐个字符地给数组赋 ...

  6. Java 语言中一个字符占几个字节?

    Java中理论说是一个字符(汉字 字母)占用两个字节. 但是在UTF-8的时候 new String("字").getBytes().length 返回的是3 表示3个字节 作者: ...

  7. C语言中的字符数组和字符串

    在C语言中,没有字符串类型,但是可以通过字符数组来模拟字符串. 字符串可以在栈上,堆上,静态区和常量区进行分配. char buf[50]  = "abc"; char buf[] ...

  8. C语言中的字符和整数之间的转换

    首先对照ascal表,查找字符和整数之间的规律: ascall 控制字符  48  0  49  1  50  2  51  3  52  4  53  5  54  6  55  7  56  8 ...

  9. 关于c语言中的字符数组和字符串指针

    先看代码: #include <stdio.h> int main(void) { ] = "; char * strTmp = "abcdefg"; int ...

随机推荐

  1. python面向对象编程(2)—— 实例属性,类属性,类方法,静态方法

    1  实例属性和类属性 类和实例都是名字空间,类是类属性的名字空间,实例则是实例属性的名字空间. 类属性可通过类或实例来访问.只有通过类名访问时,才能修改类属性的值. 例外的一种情况是,当类属性是一个 ...

  2. 团队作业—预则立&&他山之石(人月神教)

    1.团队任务 GitHub issues 1.2 团队计划 2.访谈任务 2.1采访对象 采访团队:龙威零式 采访时间:2017.10.23 采访形式:微信群 2.2采访内容 问:你们选题的时候有哪些 ...

  3. 【转】用JS创建json数据,并且可以动态往json数据里面添加新值,也可以修改值。

    原文地址:http://blog.csdn.net/panlingfan/article/details/45562893/ 函数不需要 return,因为 json 对象会被函数直接修改. var ...

  4. Java虚拟机9:垃圾收集(GC)-4(垃圾收集器)

    1.前言 垃圾收集器是前一章垃圾收集算法理论知识的具体实现了,不同虚拟机所提供的垃圾收集器可能会有很大差别,另外我们必须提前说明一个道理:没有最好的垃圾收集器,更加没有万能的收集器,只能选择对具体应用 ...

  5. 随手练——LintCode 433 - 小岛数量

    LintCode 433: https://www.lintcode.com/problem/number-of-islands/description LintCode 434: https://w ...

  6. 【PHP】 mysqli_autocommit() 函数

    //获取每一篇文章的内容 function getPost($f_parent_id, $f_title, $f_username, $f_board_id,$f_post_time, $f_ip,$ ...

  7. Java之关于JSTL引入问题

    错误信息:Can not find the tag library descriptor for “http://java.sun.com/jstl/core”JSTL taglib需要jstl.ja ...

  8. selenium断言的分类

    操作(action).辅助(accessors)和断言(assertion): 操作action: 模拟用户与 Web 应用程序的交互. 辅助accessors: 这是辅助工具.用于检查应用程序的状态 ...

  9. spring aop,静态及动态代理例子

    @Aspect@Componentpublic class AopText { @Pointcut("execution(public * com.llf.service.*Service. ...

  10. web测试--数据分层测试

    转自:51Testing 测试效率低下?很多时间都在等程序开发功能,直到界面层展现出来数据后,我们才能介入测试,然后忙的焦头烂额,上线前心里还没底.亦或者发现一个Bug,发给程序猿A查,程序猿A说,可 ...