字符串是golang的基本类型之一,也是常用的值类型。go的标准库有两个对字符串相关操作包值得利用。
strings包主要实现了利用简便的函数来操作UTF-8编码的字符串。
1,Contains(s1 string,s2 string)bool
s1中是否包含字符串s2
fmt.Println(strings.Contains("街角魔族是最好看的动漫", "街角魔族"))
fmt.Println(strings.Contains("up sail の right", "の"))
fmt.Println(strings.Contains("asdf", "sf"))//例子3
fmt.Println(strings.Contains("", ""))
输出:
true
true
false
true
从这里就能看出来strings包中所描述的“操作UTF-8编码的字符串”是什么意思。篇幅所限对于Containers还有其几个扩展方法这里仅介绍意思不展示使用了和Containers用法一摸一样,以下几个例子也是一样不再赘述了。
func ContainsRune(s string, r rune) bool
判断字符串s是否包含utf-8码值r。
func ContainsAny(s, chars string) bool
判断字符串s是否包含字符串chars中的任一字符。这里带入上面代码例子3将输出true。
2,EqualFold(s, t string) bool
判断在Unicode大小写不敏感下s和t是否是相等,而s和t解码为UTF-8字符串,这是大小写不敏感的一种更普遍的形式。
fmt.Println(strings.EqualFold("KÖŞEDEKI şeytan En IYI animasyondur!", "köşedeki ŞEYTAN eN iyi ANIMASYONDUR!"))
输出:
true
3,HasPrefix(s, prefix string) bool
判断s是否有前缀prefix
fmt.Println(strings.HasPrefix("街角魔族是最好看的动漫","街角"))
输出:
true
对于HasPrefix还有其几个扩展方法:
HasSuffix(s, suffix string) bool
判断s是否有后缀Suffix
4,func Count(s, sep string) int
字符串s中包含几个sep子字符串
fmt.Println(strings.Count("街角魔族是最好看的动漫", "街角魔族"))
fmt.Println(strings.Count("up sail の right", "君の名"))
输出:
1
0
5,func Index(s, sep string) int
子串sep在字符串s中的第一次出现位置,不存在返回-1,下标从0开始算
fmt.Println(strings.Index("街角魔族是最好看的动漫", "街角魔族"))
fmt.Println(strings.Index("up sail の right", "君の名"))//例子2
输出:
0
-1
对于Index还有其几个扩展方法:
func IndexByte(s string, c byte) int
字符c在s中第一次出现的位置,不存在则返回-1。
func IndexRune(s string, r rune) int
utf-8码值r在s中第一次出现的位置,不存在则返回-1。
func IndexAny(s, chars string) int
字符串chars中的任一utf-8码值在s中第一次出现的位置,如果不存在或者chars为空字符串则返回-1。这里带入上面代码例子2将输出8。
func IndexFunc(s string, f func(rune) bool) int
s中第一个满足函数f的位置i(该处的utf-8码值r满足f®==true),不存在则返回-1。
func LastIndex(s, sep string) int
子串sep在字符串s中最后一次出现的位置,不存在则返回-1。
func LastIndexByte(s string, c byte) int
字符c在s中最后一次出现的位置,不存在则返回-1。
func LastIndexAny(s, chars string) int
字符串chars中的任一utf-8码值在s中最后一次出现的位置,如不存在或者chars为空字符串则返回-1。
func LastIndexFunc(s string, f func(rune) bool) int
s中最后一个满足函数f的unicode码值的位置i,不存在则返回-1。
这里的<最后一个满足函数f的unicode码值位置>其实就是字符串s里的每个字符都拿出来让你自己写个函数判断一下对不对就好了,我们一般主要用法还是调用一下unicode包的函数,关于unicode包大家有兴趣自行百度这里仅介绍几个常见例子:
//这里编码由于是unicode因此一个中文算3位
fmt.Println(strings.LastIndexFunc("街角魔族是世界第1好看动漫",
//出现字符'好'的位置
func(r rune) bool {
if r == '好' {
return true
}
return false
}))
fmt.Println(strings.LastIndexFunc(" right!", func(r rune) bool {
return !unicode.IsSpace(r) && !unicode.IsNumber(r) //最后一个不是空格且不是数字的位置
}))
fmt.Println(strings.LastIndexFunc("123 ChopinB", unicode.IsLower)) //最后一个是小写字母的
输出:
25
6
9
6,Title(s string) string将s内的所有单词首字母转换为大写
fmt.Println(strings.Title("hello boy you very 帅 give me a 赞"))
输出
Hello Boy You Very 帅 Give Me A 赞
对于Title还有其几个扩展方法:
ToLower(s string) string
将s内的所有字母转换为小写
ToLowerSpecial(c unicode.SpecialCase, s string) string
使用规定的字符映射c,将s内的所有字母转换为小写//存疑往下看
ToTitle(s string) string
将s内的所有字母转换为大写//感觉效果和ToUpper一摸一样
ToTitleSpecial(c unicode.SpecialCase, s string) string
使用规定的字符映射c,将s内的所有字母转换为大写//存疑往下看
ToUpper(s string) string
将s内的所有字母转换为大写
ToUpperSpecial(c unicode.SpecialCase, s string) string
使用规定的字符映射c,将s内的所有字母转换为大写。
其实这里的c和上面的func LastIndexFunc(s string, f func(rune) bool) int
中的函数f用法一样都是调unicode包里的函数,下面再出现函数f或 unicode.SpecialCase就不再赘述了。
//unicode.TurkishCase土耳其语
fmt.Println(strings.ToUpperSpecial(unicode.TurkishCase, "köşedeki şeytan en iyi animasyondur"))
输出:
KÖŞEDEKİ ŞEYTAN EN İYİ ANİMASYONDUR
ToValidUTF8(s, replacement string) string
将s内不属于utf-8范围的字符替换为replacement子串,如果不存在非法字符则无事发生。
fmt.Println(strings.ToValidUTF8("街角\xF3魔族是最好的动漫\x80", "替换字符"))
fmt.Println(strings.ToValidUTF8("街角魔族是最好的动漫", "替换字符"))
输出:
街角替换字符魔族是最好的动漫替换字符
街角魔族是最好的动漫
在需要筛选检测的内容中使用还是很好用的
7,Replace(s, old, new string, n int) string将字符串s内的old字符串替换为new字符串,n为替换个数,如果old是空的,则在字符串的开头和每个UTF-8序列之后匹配,产生k+1的k-rune字符串的替换。如果n<0,则替换数没有限制。
fmt.Println(strings.Replace("街角魔族是好好好的动漫", "好", "最好", 2))
fmt.Println(strings.Replace("街角魔族是好好好的动漫", "好", "最好", -1))
fmt.Println(strings.Replace("街角魔族是最好看的动漫", "", "呐", 2))
输出:
街角魔族是最好最好好的动漫
街角魔族是最好最好最好的动漫
呐街呐角魔族是最好看的动漫
对于Replace还有其几个扩展方法:
ReplaceAll(s, old, new string) string
此方法等于Replace(s, old, new, -1)
源码⬇其实这里很多方法都是这样,如Trim调用的就是TrimFunc。
func ReplaceAll(s, old, new string) string {
return Replace(s, old, new, -1)
}
对于Replace还有对应的结构体Replacer,利用这个类中的NewReplacer(oldnew ...string) *Replacer
就能创建出来,可用其实现更为复杂的替换操作
r := strings.NewReplacer("好", "最好", "<", "<", "&rt;", ">")//一新一旧交替更换
fmt.Println(r.Replace("<h1&rt;街角魔族是好看的动漫</h1&rt;"))
输出:
<h1>街角魔族是最好看的动漫</h1>
还有一个WriteString就不演示了等写io的时候说说。
8,Map(mapping func(rune) rune, s string) string
根据mapping函数修改字符串的所有字符。如果mapping返回一个负值,则该字符将从字符串中删除,不需要替换。
fmt.Println(strings.Map(func(r rune) rune {
switch {
case r == '不':
return -1
case r == '特':
return '最'
case r == ' ':
return '看'
}
return r
}, "街角魔族是特不好 的动漫"))
街角魔族是最好看的动漫
9,Trim(s string, cutset string) string
删除割集中包含的所有前端和尾部//不懂割集是什么的看个例子你就懂了
fmt.Println(strings.Trim("说得好 街角魔族是最好的动漫 说得对", "说得好"))
fmt.Println(strings.Trim("? 街角魔族是最好的动漫 !", "? !"))//这里的前后相对应
输出:
街角魔族是最好的动漫 说得对
街角魔族是最好的动漫
对于Trim还有其几个扩展方法:
TrimFunc(s string, f func(rune) bool) string
删除前端和尾部都满足函数f的字符串
TrimLeft(s string, cutset string) string
删除割集中包含的所有前端字符串。如果是删除前缀请用TrimPrefix
TrimLeftFunc(s string, f func(rune) bool) string
删除s字符串前端都满足函数f的子字符串
TrimPrefix(s, prefix string) string
删除s前缀prefix
TrimRight(s string, cutset string) string
删除割集中包含的所有尾部字符串。如果是删除后缀请用TrimSuffix
TrimRightFunc(s string, f func(rune) bool) string
删除s字符串尾部都满足函数f的子字符串
TrimSpace(s string) string
删除s前后端(由Unicode定义)的所有空格
TrimSuffix(s, suffix string) string
删除s后缀suffix
10,Fields(s string) []string
返回由空格(unicode.IsSpace确定,可以是一到多个连续的空白字符)分割的字符串切片。如果字符串全部是空白或者是空字符串的话,会返回空切片。
str := strings.Fields(" 街角 魔族 是最好 的动漫 ")
for _, v := range str {
fmt.Println(v)
}
对于Fields还有其几个扩展方法:
FieldsFunc(s string, f func(rune) bool) []string
返回满足函数f分割的字符串切片。如果字符串全部满足函数f或者是空字符串的话,会返回空切片
11,Split(s, sep string) []string
返回由sep分割的字符串切片,如果s不包含sep,原样返回长度为1的字符串切片,如果sep为空字符串返回每一个字符的切片,如果s和sep都是空的,Split将返回一个空切片。相邻sep依旧会分隔中间的空字符串。
s := strings.Split("街角,魔族,是最好,的动漫,", ",")//例1
fmt.Println(s, "len:", len(s))
s2 := strings.Split("街角魔族是最好的动漫", "")//例2
fmt.Println(s2, "len:", len(s2))
s3 := strings.Split("街角,魔族,,,是最好,,,的动漫", ",")//例3
fmt.Println(s3, "len:", len(s3))
输出:
[街角 魔族 是最好 的动漫 ] len: 5
[街 角 魔 族 是 最 好 的 动 漫] len: 10
[街角 魔族 是最好 的动漫] len: 8
这里例1最后一个逗号后没东西依旧算一个分隔切出了一个空字符串。
例2用空字符分隔则返回字符切片。
例3用逗号分隔逗号与逗号之间的空字符依旧分割了出来。
对于Split还有其几个扩展方法:
SplitAfter(s, sep string) []string
用法与Split一样,但切片内容保留了分隔符
SplitAfterN(s, sep string, n int) []string
用法与SplitAfter一样,增加了参数n决定返回的切片的数目。n > 0 : 返回的切片最多n个子字符串;最后一个子字符串包含未进行切割的部分,n == 0: 返回nil,n < 0 : 返回所有的子字符串组成的切片
SplitN(s, sep string, n int) []string
用法与Split一样,增加了参数n决定返回的切片的数目。n > 0 : 返回的切片最多n个子字符串;最后一个子字符串包含未进行切割的部分,n == 0: 返回nil,n < 0 : 返回所有的子字符串组成的切片
12,Repeat(s string, count int) string
将s重复count次。如果count为负数或(len(S)*count)溢出,则会引起panic。
fmt.Println("街角魔族是", strings.Repeat("最", 2), "好看的动漫")
输出:
街角魔族是 最最 好看的动漫
13,Join(a []string, sep string) string
将a内的所有字符串用sep相连
a := []string{“街角”, “魔族”, “是最好看”, “的动漫”}
fmt.Println(strings.Join(a, ""))
fmt.Println(strings.Join(a, "~"))
输出:
街角魔族是最好看的动漫
街角~魔族~是最好看~的动漫
如果只是单纯的连接字符串不建议使用这个方法,在没有一个现成的a []string时,效率巨低,用bytes包内Buffer结构体中的WriterString方法连接会快如闪电(以上仅为大批量连接,就以少数string连接时用str + = str2
的可读性更好)。
strings包内还有Reader和Builder两个结构体,不过不在strings里说了,等有机会写io的时候说。
strconv包实现了对基本数据类型的字符串表示形式的转换。里面内置了
常量
const IntSize = intSize
数值位数
变量
1,ErrRange = errors.New("value out of range")
目标类型的值超出范围
2,ErrSyntax = errors.New("invalid syntax")
某个值对目标类型没有正确的语法。
1、AppendBool(dst []byte, b bool) []byte
根据b的值将“true”或“false”追加到dst并返回扩展缓冲区。
b := []byte("街角魔族是最好看的动漫,对于否?")
fmt.Println(string(strconv.AppendBool(b, true)))
//没强转string会显示码值
fmt.Println(strconv.AppendBool([]byte{'y', 'e', 's'}, true))
输出:
街角魔族是最好看的动漫,对于否?true
[121 101 115 116 114 117 101]
对于AppendBool还有其几个类似方法:
AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte
根据f的值将浮点数追加到dst并返回字节切片。
其中
AppendInt(dst []byte, i int64, base int) []byte
根据i的值将整数追加到dst并返回字节切片。base代表进制( 2 <= base <= 36),结果使用小写字母“a”到“z”表示数字值>=10。
AppendQuote(dst []byte, s string) []byte
根据s的值将字符串追加到dst并返回字节切片。
AppendQuoteRune(dst []byte, r rune) []byte
根据r的值将字符追加到dst并返回字节切片。
AppendQuoteRuneToASCII(dst []byte, r rune) []byte
根据r的值将字符追加到dst并返回字节切片。
AppendQuoteRuneToGraphic(dst []byte, r rune) []byte
根据r的值将字符追加到dst并返回字节切片。
AppendQuoteToASCII(dst []byte, s string) []byte
根据s的值将字符串追加到dst并返回字节切片。
AppendQuoteToGraphic(dst []byte, s string) []byte
根据s的值将字符串追加到dst并返回字节切片。
AppendUint(dst []byte, i uint64, base int) []byte
根据i的值将正整数追加到dst并返回字节切片。
以上strconv.Appendxxx函数皆可等价于内置函数Append(dst,strconv.Formatxxx(value)...)
strconv.AppendQuotexxx等价于Append(dst,strconv.Quotexxx(value)...)
可见源码⬇
func AppendBool(dst []byte, b bool) []byte {
if b {
return append(dst, "true"...)
}
return append(dst, "false"...)
}
func AppendQuote(dst []byte, s string) []byte {
return appendQuotedWith(dst, s, '"', false, false)
}
func Quote(s string) string {
return quoteWith(s, '"', false, false)
}
func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string {
return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote, ASCIIonly, graphicOnly))
}
对于AppendQuotexxx中的Quotexxx究竟做了些什么,我们在下面转换中在具体提及。使用内置函数append(dst,strconv.xxx()…) 还是strconv.appendxxx() 主要看你们的使用习惯。
2,ParseInt(s string, base int, bitSize int) (i int64, err error)
返回字符串表示的整数值,接受正负号。
fmt.Println(strconv.ParseInt("-123", 0, 0))
fmt.Println(strconv.ParseInt("+0x123", 0, 0))
fmt.Println(strconv.ParseInt("12a", 16, 0))
fmt.Println(strconv.ParseInt("123456700000", 8, 8))//超出范围
fmt.Println(strconv.ParseInt("12a", 10, 64))//10进制没有a
输出:
-123 <nil>
291 <nil>
298 <nil>
127 strconv.ParseInt: parsing "123456700000": value out of range
0 strconv.ParseInt: parsing "12a": invalid syntax
对于ParseInt还有其几个类似方法:
ParseFloat(s string, bitSize int) (float64, error)
将字符串s转换为浮点数。
ParseBool(str string) (bool, error)
将字符串s转换为bool它接受1、0、t、f、T、F、true、false、True、False、TRUE、FALSE;否则返回错误
ParseUint(s string, base int, bitSize int) (uint64, error)
ParseUint与ParseInt类似,但用于无符号数字。
3,Atoi(s string) (int, error)
Atoi等效于ParseInt(s,10,0),int转换为string类型。
4,FormatFloat(f float64, fmt byte, prec, bitSize int) string
根据f的值将浮点数转换为string。
其中
fmt.Println(strconv.FormatFloat(12323423.141234234, 'f', -1, 64))
fmt.Println(strconv.FormatFloat(3.14123234234234, 'b', -1, 64))
//小数点后五位
fmt.Println(strconv.FormatFloat(3232323.14234234234234, 'e', 5, 64))
//指数较大自动选择e
fmt.Println(strconv.FormatFloat(2342343.14123234234234, 'g', -1, 64))
//值数较小自动选择f
fmt.Println(strconv.FormatFloat(3.14, 'g', -1, 64))
输出
12323423.141232342
7073426403228556p-51
3.23232e+06
2.3423431412323425e+06
3.14
对于FormatFloat还有其几个类似方法:
FormatBool(b bool) string
根据b的值返回“true”或“false
FormatInt(i int64, base int) string
根据i的值将整数转换为字符串,base为进制( 2 <= base <= 36),结果使用小写字母“a”到“z”表示数字值>=10。
func FormatUint(i uint64, base int) string
根据i的值将正整数转换为字符串,base为进制( 2 <= base <= 36),结果使用小写字母“a”到“z”表示数字值>=10。
5,Itoa(i int) string
等效于FormatInt(int 64(i),10),int转换为string类型。
6,CanBackquote(s string) bool
字符串s是否可以不变地表示为单行反引号字符串,而不需要制表符以外的控制字符。
fmt.Println(strconv.CanBackquote("街角魔族是最好看的动漫\t"))//制表符ok
fmt.Println(strconv.CanBackquote("街角魔族是最好看的动漫\n"))//换行不ok
输出:
true
false
7,IsGraphic(r rune) bool
判断字符 r 是否为一个“图形字符”, “图形字符”包括字母、标记、数字、标点、符号、空格,他们分别对应于 L、M、N、P、S、Zs 类别,这些类别是 RangeTable 类型,存储了相应类别的字符范围
fmt.Println(strconv.IsGraphic('a'))
fmt.Println(strconv.IsGraphic('啊'))
fmt.Println(strconv.IsGraphic(' '))
fmt.Println(strconv.IsGraphic('\n'))
输出:
true
true
true
false
对于IsGraphic还有其几个类似方法:
IsPrint(r rune) bool
判断r是否为Go定义的可打印字符,其定义与Unicode.IsPrint相同:字母(广义上的中文、土耳其都算)、数字、标点符号、符号和ASCII空格。
8,Quote(s string) string
返回字符串s在go语法下的字面值表示,由IsPrint定义的不可打印字符会进行转义。(如\t,\n,\xFF,\u0100)
str := "\"街角魔族是 最好看的动漫 \n\xff\""
fmt.Println(str)//打印未进行字面值转义的str
//打印转义后的str
fmt.Println(strconv.Quote(str))
//打印反引号
fmt.Println(`\"街角魔族是 最好看的动漫 \n\xff\"`)
输出:
"街角魔族是 最好看的动漫
�"
"\"街角魔族是\t最好看的动漫 \n\xff\""
\"街角魔族是 最好看的动漫 \n\xff\"
对于Quote还有其几个类似方法:
QuoteRune(r rune) string
返回字符r在go语法下的字面值表示,控制字符、由IsPrint定义的不可打印字符会进行转义。(\t,\n,\xFF,\u0100)
QuoteRuneToASCII(r rune) string
返回字符r在go语法下的字面值表示,由IsPrint定义的非ASCII字符、不可打印字符会进行转义。(\t,\n,\xFF,\u0100)
QuoteRuneToGraphic(r rune) string
返回字符r在go语法下的字面值表示,如果不是由IsGrapch定义的Unicode图形字符,将进行转义。(\t,\n,\xFF,\u0100)
QuoteToASCII(s string) string
返回字符串s在go语法下的字面值表示,由IsPrint定义的非ASCII字符、不可打印字符会进行转义。(\t,\n,\xFF,\u0100)
QuoteToGraphic(s string) string
返回字符串s在go语法下的字面值表示,如果不是由IsGrapch定义的Unicode图形字符,将进行转义。(\t,\n,\xFF,\u0100)
9,Unquote(s string) (string, error)
如果s是一个单引号、双引号、反引号包围的go语法字符串,解析它并返回它表示的值。(如果s是单引号,会认为s是go字符字面值,返回一个单字符的字符串)
//必须用单引号、双引号、反引号中的一个将内容括起来
s, err := strconv.Unquote("街角魔族是最好看的动漫")
fmt.Printf("%q, %v\n", s, err)
//如果是字符串需要用双引号括起来
s, err = strconv.Unquote("\"街角 魔族是最好看的动漫\"")
fmt.Printf("%q, %v\n", s, err)
//用反引号也行
s, err = strconv.Unquote("`街角 魔族是最好看的动漫`")
fmt.Printf("%q, %v\n", s, err)
//单引号中只允许使用单个字符
s, err = strconv.Unquote("'\xff'")
fmt.Printf("%q, %v\n", s, err)
//单引号中使用多个字符将报错
s, err = strconv.Unquote("'街角魔族是最好看的动漫'")
fmt.Printf("%q, %v\n", s, err)
输出:
"", invalid syntax
"街角\t魔族是最好看的动漫",
"街角\t魔族是最好看的动漫",
"�",
"", invalid syntax
10,UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error)
如果s是一个表示字符的go语法字符串,解析它并返回四个值:
v, mb, t, err := strconv.UnquoteChar(`\"Fran & Freddie's Diner\"`, '"')
if err != nil {
log.Fatal(err)
}
fmt.Println("value:", string(v))
fmt.Println("multibyte:", mb)
fmt.Println("tail:", t)
输出:
value: "
multibyte: false
tail: Fran & Freddie's Diner\"
以上就是string的所有内容了。
utf8包实现了函数和常量,以支持用UTF-8编码的文本。其中还内含rune和utf-8编码byte之间相互转换的函数。见https://en.wikipedia.org/wiki/UTF-8
常量
const (
RuneError = ‘\uFFFD’ //错误的Rune或"Unicode replacement character"
RuneSelf = 0x80 // RuneSelf下面的字符以单个字节表示为自己
MaxRune = ‘\U0010FFFF’ // 最大的合法unicode码值
UTFMax = 4 // 最大的utf-8编码的unicode字符长度
)
编码所必需的常量。
1,DecodeRune(p []byte) (r rune, size int)
函数解码p开始位置的第一个utf-8编码的码值,返回该码值和编码的字节数。如果编码不合法,会返回(RuneError, 1)。该返回值在正确的utf-8编码情况下是不可能返回的。
如果一个utf-8编码序列格式不正确,或者编码的码值超出utf-8合法码值的范围,或者不是该码值的最短编码,该编码序列即是不合法的。函数不会执行其他的验证。
s := []byte("街角魔族是最好看的动漫")
code, size := utf8.DecodeRune(s)
//中文占三位
fmt.Println("rune:", string(code), "size:", size)
s2 := []byte("\n街角魔族是最好看的动漫")
code2, size2 := utf8.DecodeRune(s2)
fmt.Println("rune:", string(code2), "size:", size2)
输出:
rune: 街 size: 3
rune:
size: 1
对于DecodeRune还有其几个类似方法:
DecodeRuneInString(s string) (r rune, size int)
类似于DecodeRune,但是它的输入是一个字符串。
DecodeLastRune(p []byte) (r rune, size int)
解码p最后一个utf-8编码的码值,返回该码值和编码的字节数。如果编码不合法,会返回(RuneError, 1)。该返回值在正确的utf-8编码情况下是不可能返回的。
如果一个utf-8编码序列格式不正确,或者编码的码值超出utf-8合法码值的范围,或者不是该码值的最短编码,该编码序列即是不合法的。函数不会执行其他的验证。
DecodeLastRuneInString(s string) (r rune, size int)
类似于DecodeRuneLastRune,但是它的输入是一个字符串。
2,EncodeRune(p []byte, r rune) int将字符r写入字节切片p(必须有足够的长度),它返回写入的字节数。
r := 'の'
buf := make([]byte, 3)
n := utf8.EncodeRune(buf, r)
fmt.Println(n, ",", buf)
输出:
3 , [227 129 174]
3,RuneCount(p []byte) int
返回p中的utf-8编码的码值的个数。错误或者不完整的编码会被视为宽度1字节的单个码值。
buf := []byte("街角魔族是全宇宙第1好看的动漫")
fmt.Println("bytes =", len(buf))
fmt.Println("runes =", utf8.RuneCount(buf))
输出
bytes = 43
runes = 15
对于RuneCount还有其几个类似方法:
RuneCountInString(s string) (n int)
与RuneCount类似,但其输入是一个字符串。
4,RuneLen(r rune) int
返回编码rune所需的字节数。如果符文不是在UTF-8中编码的有效值,则返回-1。
fmt.Println(utf8.RuneLen('\n'))
fmt.Println(utf8.RuneLen('好'))
输出:
1
3
5,FullRune(p []byte) bool
判断字节切片p中的字节是否以rune的完整UTF-8编码开始。无效的编码被认为是完全的符文,因为它将转换为宽度为1的错误。
buf := []byte("街角魔族是全宇宙第1好看的动漫")
fmt.Println(utf8.FullRune(buf))
fmt.Println(utf8.FullRune(buf[:2]))
输出:
true
false
对于FullRune还有其几个类似方法:
FullRuneInString(s string) bool
与FullRune类似,但是它的输入是一个字符串。
RuneStart(b byte) bool
判断字节b是否可以是编码的、可能无效的Rune的第一个字节。第二字节和后续字节总是将前两位设置为10。
6,Valid(p []byte) bool
判断字节切片p是否完全由有效的UTF-8编码符文组成。
valid := []byte("街角魔族是全宇宙第1好看的动漫")
invalid := []byte{0xff}
fmt.Println(utf8.Valid(valid))
fmt.Println(utf8.Valid(invalid))
输出:
true
false
对于Valid还有其几个类似方法:
ValidRune(r rune) bool
判断字符r是否可以合法编码为UTF-8。超出范围的代码点或代理项的一半是非法的。
ValidString(s string) bool
判断字符串s是否完全由有效的UTF-8编码的rune组成.
对于字符处理还有bytes包可供我们选择,但是由于bytes包与strings的重合率太高,这里就不再写了,不过可以给大家一个高效连接字符串的代码:
//method1
start1 := time.Now()
b := make([]byte, 100)
buf := bytes.NewBuffer(b)
for i := 0; i < 20000; i++ {
buf.WriteString("街角魔族是最好看的动漫")
}
end1 := time.Now()
//要取成字符串直接用buf.String()就好了
fmt.Println(end1.Sub(start1))
//method2
start2 := time.Now()
s := ""
st := "街角魔族是最好看的动漫"
for i := 0; i < 20000; i++ {
s += st
}
end2 := time.Now()
fmt.Println(end2.Sub(start2))
输出:
998.4µs
1.7304787s
对于rune不知道有没有第一次接触的小伙伴感觉很蒙啊,其实这就是int32的别名,rune==int32,只不过为了不让int32这个数值类型既当爹又当妈的语义不明确,因此取了格rune这个名字来专门代表字符,还有byte也是同理,byte == uint8。
源代码⬇
// byte is an alias for uint8 and is equivalent to uint8 in all ways. It is
// used, by convention, to distinguish byte values from 8-bit unsigned
// integer values.
type byte = uint8
// rune is an alias for int32 and is equivalent to int32 in all ways. It is
// used, by convention, to distinguish character values from integer values.
type rune = int32
随便举个实例utf8.Valid(p []byte) bool
用[]uint8一样运行
valid := []uint8("街角魔族是全宇宙第1好看的动漫")
invalid := []uint8{0xff}
fmt.Println(utf8.Valid(valid))
fmt.Println(utf8.Valid(invalid))
输出:
true
false
看到这里以后再出现字符转换,类型互换,字符操作之类的问题是不是更好解决了呢?