golang 字符处理/转换/操作(string/byte/rune)大全

string

字符串是golang的基本类型之一,也是常用的值类型。go的标准库有两个对字符串相关操作包值得利用。

strings

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) intutf-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) ints中第一个满足函数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) ints中最后一个满足函数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("好", "最好", "&lt;", "<", "&rt;", ">")//一新一旧交替更换
fmt.Println(r.Replace("&lt;h1&rt;街角魔族是好看的动漫&lt;/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

strconv包实现了对基本数据类型的字符串表示形式的转换。里面内置了
常量
const IntSize = intSize数值位数
变量
1,ErrRange = errors.New("value out of range")目标类型的值超出范围
2,ErrSyntax = errors.New("invalid syntax")某个值对目标类型没有正确的语法。

string追加

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并返回字节切片。
其中

  1. fmt表示格式:‘f’(-ddd.dddd)、‘b’(-ddddp±ddd,指数为二进制)、‘e’(-d.dddde±dd,十进制指数)、‘E’(-d.ddddE±dd,十进制指数)、‘g’(指数很大时用’e’格式,否则’f’格式)、‘G’(指数很大时用’E’格式,否则’f’格式)。
  2. prec控制精度(排除指数部分):对’f’、‘e’、‘E’,它表示小数点后的数字个数;对’g’、‘G’,它控制总的数字个数。如果prec 为-1,则代表使用最少数量的、但又必需的数字来表示f。
  3. bitSize表示f的来源类型(32:float32、64:float64),会据此进行舍入。

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() 主要看你们的使用习惯。

string转其他类型

2,ParseInt(s string, base int, bitSize int) (i int64, err error)返回字符串表示的整数值,接受正负号。

  1. base指定进制(2到36),如果base为0,则会从字符串前置判断,"0x"是16进制,"0"是8进制,否则是10进制;
  2. bitSize指定结果必须能无溢出赋值的整数类型,0、8、16、32、64 分别代表 int、int8、int16、int32、int64;返回的err是*NumErr类型的,如果语法有误,err.Error =
    ErrSyntax;如果结果超出类型范围err.Error = ErrRange。
	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转换为浮点数。

  1. 精度由bitSize指定:32表示float32,64表示float64。当bitSize=32时,结果仍然具有float64类型,但它可以转换为float32而不更改其值。
  2. ParseFloat接受十进制和十六进制浮点数语法。如果s格式正确且接近有效的浮点数,则返回使用IEEE754无偏舍入的最接近的浮点数。(仅当十六进制表示中的位比尾数中的位多时,解析十六进制浮点值才会循环。)
  3. ParseFloat返回的err是*NumErr类型的,如果语法有误,err.Error = ErrSyntax;如果与给定大小的最大浮点数相差超过1/2 ULP,则ParseFloat返回f=±Inf,错误,err.Err = ErrRange。
  4. ParseFloat将字符串"NaN","+Inf"和 "-Inf"识别为它们各自的特殊浮点值。匹配时忽略大小写。

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类型。

其他类型转string

4,FormatFloat(f float64, fmt byte, prec, bitSize int) string根据f的值将浮点数转换为string。
其中

  1. fmt表示格式:‘f’(-ddd.dddd)、‘b’(-ddddp±ddd,指数为二进制)、‘e’(-d.dddde±dd,十进制指数)、‘E’(-d.ddddE±dd,十进制指数)、‘g’(指数很大时用’e’格式,否则’f’格式)、‘G’(指数很大时用’E’格式,否则’f’格式)。
  2. prec控制精度(排除指数部分):对’f’、‘e’、‘E’,它表示小数点后的数字个数;对’g’、‘G’,它控制总的数字个数。如果prec 为-1,则代表使用最少数量的、但又必需的数字来表示f。
  3. bitSize表示f的来源类型(32:float32、64:float64),会据此进行舍入。
	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魔族是最好看的动漫", <nil>
"街角\t魔族是最好看的动漫", <nil>
"�", <nil>
"", invalid syntax

10,UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error)如果s是一个表示字符的go语法字符串,解析它并返回四个值:

  1. value,表示一个rune值或者一个byte值
  2. multibyte,表示value是否是一个多字节的utf-8字符
  3. tail,表示字符串剩余的部分
  4. err,表示可能存在的语法错误
    参数quote为单引号时,函数认为单引号是语法字符,不接受未转义的单引号;双引号时,函数认为双引号是语法字符,不接受未转义的双引号;如果是零值,函数把单引号和双引号当成普通字符。
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

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

看到这里以后再出现字符转换,类型互换,字符操作之类的问题是不是更好解决了呢?

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在 `golang.org/x/net/websocket` 包中,并没有内置的路由功能。如果您想要使用该包处理不同的 WebSocket 路由,您可以结合使用 `net/http` 包的路由功能来实现。以下是一个示例代码: ```go package main import ( "log" "net/http" "golang.org/x/net/websocket" ) func main() { http.Handle("/ws/foo", websocket.Handler(handleFooWebSocket)) http.Handle("/ws/bar", websocket.Handler(handleBarWebSocket)) log.Println("WebSocket 服务器启动,监听端口 8080") err := http.ListenAndServe(":8080", nil) if err != nil { log.Fatal("WebSocket 服务器启动失败:", err) } } func handleFooWebSocket(conn *websocket.Conn) { // 处理 /ws/foo 路由的 WebSocket 连接逻辑 // ... } func handleBarWebSocket(conn *websocket.Conn) { // 处理 /ws/bar 路由的 WebSocket 连接逻辑 // ... } ``` 在上述示例中,我们使用 `net/http` 包的 `http.Handle` 函数来定义不同的路由,并使用 `websocket.Handler` 将每个路由的处理函数转换为 WebSocket 的处理器。 在这个示例中,我们定义了两个 WebSocket 路由,`/ws/foo` 和 `/ws/bar`。当有 WebSocket 连接请求到达时,路由器会将请求传递给相应的处理函数 `handleFooWebSocket` 或 `handleBarWebSocket` 进行处理。 您可以根据实际需求添加更多的路由和处理函数。 请注意,`golang.org/x/net/websocket` 包现在已经被废弃,推荐使用 `github.com/gorilla/websocket` 包来处理 WebSocket 连接。`github.com/gorilla/websocket` 包提供了更多的功能和灵活性。 希望以上信息对您有所帮助!如果您还有其他问题,请随时提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值