Go 语言字符串使用方式与技巧

发布时间 2023-12-11 07:56:28作者: 技术颜良

Go 语言字符串使用方式与技巧

大家好,我是 frank。
欢迎大家点击标题下方蓝色文字「Golang 语言开发栈」关注公众号。
公众号主页点击右上角三个点图标,
设为星标,第一时间接收推送文章。
文末扫码,加群一起学 Golang 语言。

01 

介绍

关于 Go 语言字符串的使用,我们需要了解标准库 strconv 和标准库 strings 的使用方式,它们分别用于字符串类型转换和字符串操作。

本文我们重点介绍 Go 语言字符串使用方式与技巧。

02 

字符串类型转换

Go 语言是强类型语言,在使用 Go 语言时,通常会遇到需要将字符串与其它类型相互转换的场景。

此时,我们可以使用标准库 strconv

字符串 to 布尔

示例代码:

func main() {
 v := "true"
 if s, err := strconv.ParseBool(v); err == nil {
  fmt.Printf("%T, %v\n", s, s)
 }
}

输出结果:

bool, true

阅读上面这段代码,我们使用 func ParseBool(str string) (bool, error) 将字符串转换为布尔。需要注意的是,该函数接收参数的值是有限制的,除了 1、t、T、TRUE、true、True、0、f、F、FALSE、false、False 之外,其它任何值都会返回 error。

字符串 to 浮点型

示例代码:

func main() {
 v := "3.1415926535"
 if s, err := strconv.ParseFloat(v, 32); err == nil {
  fmt.Printf("%T, %v\n", s, s)
 }
 if s, err := strconv.ParseFloat(v, 64); err == nil {
  fmt.Printf("%T, %v\n", s, s)
 }
 if s, err := strconv.ParseFloat("NaN", 32); err == nil {
  fmt.Printf("%T, %v\n", s, s)
 }
 // ParseFloat is case insensitive
 if s, err := strconv.ParseFloat("nan", 32); err == nil {
  fmt.Printf("%T, %v\n", s, s)
 }
 if s, err := strconv.ParseFloat("inf", 32); err == nil {
  fmt.Printf("%T, %v\n", s, s)
 }
 if s, err := strconv.ParseFloat("+Inf", 32); err == nil {
  fmt.Printf("%T, %v\n", s, s)
 }
 if s, err := strconv.ParseFloat("-Inf", 32); err == nil {
  fmt.Printf("%T, %v\n", s, s)
 }
 if s, err := strconv.ParseFloat("-0", 32); err == nil {
  fmt.Printf("%T, %v\n", s, s)
 }
 if s, err := strconv.ParseFloat("+0", 32); err == nil {
  fmt.Printf("%T, %v\n", s, s)
 }
}

输出结果:

float64, 3.1415927410125732
float64, 3.1415926535
float64, NaN
float64, NaN
float64, +Inf
float64, +Inf
float64, -Inf
float64, -0
float64, 0

阅读上面这段代码,我们使用 func ParseFloat(s string, bitSize int) (float64, error) 将字符串转换为 64 位浮点数。需要注意的是,该函数接收参数可以识别值为 NaNInf(有符号 +Inf 或 -Inf),并且忽略它们的大小写。

字符串 to 整型

示例代码:

func main() {
 v32 := "-354634382"
 if s, err := strconv.ParseInt(v32, 10, 32); err == nil {
  fmt.Printf("s:%T, %v\n", s, s)
 }
 if s1, err := strconv.ParseInt(v32, 16, 32); err == nil {
  fmt.Printf("s1:%T, %v\n", s1, s1)
 }

 v64 := "-3546343826724305832"
 if s2, err := strconv.ParseInt(v64, 10, 64); err == nil {
  fmt.Printf("s2:%T, %v\n", s2, s2)
 }
 if s3, err := strconv.ParseInt(v64, 16, 64); err == nil {
  fmt.Printf("s3:%T, %v\n", s3, s3)
 }
}

输出结果:

s:int64, -354634382
s2:int64, -3546343826724305832

阅读上面这段代码,我们使用 func ParseInt(s string, base int, bitSize int) (i int64, err error) 将字符串转换为整型。

需要注意的是,该函数的第一个入参为字符串类型的数值,可以 "+" 或 "-" 符号开头;

第二个参数指定进制,它的值如果是 0,进制则以第一个参数符号后的前缀决定,例如:"0b" 为 2,"0" 或 "0o" 为 8,"0x" 为 16,否则为 10;

第三个参数指定返回结果必须符合整数类型的取值范围,它的值为 0、8、16、32 和 64,分别代表 intint8int16int32 和 int64

细心的读者朋友们可能已经发现,示例代码中,第 2 和 第 4 返回错误,原因是第二个参数指定的进制与第一个参数的数值不相符,超出取值范围。

此外,函数 func ParseUint(s string, base int, bitSize int) (uint64, error) 与之类似,但是用于无符号整数。

在实际项目开发中,十进制使用的最多,所以标准库 strconv 提供了函数 func Atoi(s string) (int, error),它的功能类似 ParseInt(s, 10, 0),需要注意的是,它的返回值类型是 int(需要注意取值范围),而不是 int64

布尔 to 字符串

示例代码:

func main() {
 v := true
 s := strconv.FormatBool(v)
 fmt.Printf("%T, %v\n", s, s)
}

输出结果:

string, true

阅读上面这段代码,我们使用 func FormatBool(b bool) string 将布尔转换为字符串。

浮点型 to 字符串

示例代码:

func main() {
 v := 3.1415926535

 s32 := strconv.FormatFloat(v, 'E', -1, 32)
 fmt.Printf("%T, %v\n", s32, s32)

 s64 := strconv.FormatFloat(v, 'E', -1, 64)
 fmt.Printf("%T, %v\n", s64, s64)

 fmt64 := strconv.FormatFloat(v, 'g', -1, 64)
 fmt.Printf("%T, %v\n", fmt64, fmt64)
}

输出结果:

string, 3.1415927E+00
string, 3.1415926535E+00
string, 3.1415926535

阅读上面这段代码,我们使用 func FormatFloat(f float64, fmt byte, prec, bitSize int) string 将浮点型转换为字符串。该函数包含 4 个参数,第一个参数是需要转换的浮点数;第二个参数是进制;第三个参数是精度,第四个参数是转换后值的取值范围。

其中,第二个参数 b 代表二进制指数;e 或 E 代表十进制指数;f 代表无进制指数;g 或 G 代表指数大时 为 e,反之为 fx 或 X 代表十六进制分数和二进制指数。

第三个参数,精度 prec 控制由 'e','E','f','g','G','x' 和 'X' 格式打印的位数(不包括指数)。对于 'e','E','f','x' 和 'X',它是小数点后的位数。对于 'g' 和 'G',它是有效数字的最大数目(去掉后面的零)。特殊精度 -1 使用所需的最小位数,以便 ParseFloat 精确返回 f

整型 to 字符串

示例代码:

func main() {
 v := int64(-42)

 s10 := strconv.FormatInt(v, 10)
 fmt.Printf("%T, %v\n", s10, s10)

 s16 := strconv.FormatInt(v, 16)
 fmt.Printf("%T, %v\n", s16, s16)
}

输出结果:

string, -42
string, -2a

阅读上面这段代码,我们使用 func FormatInt(i int64, base int) string 将整型转换为字符串。需要注意的是,第二个参数的取值范围 2 <= base <= 36

此外,函数 func FormatUint(i uint64, base int) string 与之功能类型,区别是仅用于转换无类型整数。

在实际项目开发中,十进制使用的最多,所以标准库 strconv 提供了函数 func Itoa(i int) string,它的功能类似 FormatInt(int64(i), 10),需要注意的是,该函数入参的类型是 int

03 

字符串操作

关于字符串操作,标准库 strings 提供了相关函数,我们介绍几个常用的函数。

字符串中是否包含指定字符串

示例代码:

func main() {
 fmt.Println(strings.Contains("seafood", "foo"))
 fmt.Println(strings.Contains("seafood", "bar"))
 fmt.Println(strings.Contains("seafood", ""))
 fmt.Println(strings.Contains("", ""))
}

输出结果:

true
false
true
true

阅读上面这段代码,我们使用 func Contains(s, substr string) bool 在字符串 substr 中查找 s,存在则返回 true,反之返回 false

字符串中是否包含指定字符串中任意字符

示例代码:

func main() {
 fmt.Println(strings.ContainsAny("team", "i"))
 fmt.Println(strings.ContainsAny("fail", "ui"))
 fmt.Println(strings.ContainsAny("ure", "ui"))
 fmt.Println(strings.ContainsAny("failure", "ui"))
 fmt.Println(strings.ContainsAny("foo", ""))
 fmt.Println(strings.ContainsAny("", ""))
}

输出结果:

false
true
true
true
false
false

阅读上面这段代码,我们使用 func ContainsAny(s, chars string) bool 在字符串 s 中查找是否包含字符串 chars 中任意字符,存在则返回 true,反之返回 false

删除字符串中指定字符

示例代码:

func main() {
 fmt.Print(strings.Trim("¡¡¡Hello, Gophers!!!", "!¡"))
}

输出结果:

Hello, Gophers

阅读上面这段代码,我们使用 func Trim(s, cutset string) string 删除字符串 s 中的字符 cutset

字符串转换为大写

示例代码:

func main() {
 fmt.Println(strings.ToUpper("Gopher"))
}

输出结果:

GOPHER

阅读上面这段代码,我们使用 func ToUpper(s string) string 将字符串中的字符全部转换为大写。

字符串以指定字符拆分为字符串切片

示例代码:

func main() {
 fmt.Printf("%q\n", strings.Split("a,b,c", ","))
 fmt.Printf("%q\n", strings.Split("a man a plan a canal panama", "a "))
 fmt.Printf("%q\n", strings.Split(" xyz ", ""))
 fmt.Printf("%q\n", strings.Split("", "Bernardo O'Higgins"))
}

输出结果:

["a" "b" "c"]
["" "man " "plan " "canal panama"]
[" " "x" "y" "z" " "]
[""]

阅读上面这段代码,我们使用 func Split(s, sep string) []string 将字符串 s 以字符串 sep 为分隔符,拆分为字符串切片。

字符串切片拼接为字符串

示例代码:

func main() {
 s := []string{"foo", "bar", "baz"}
 fmt.Println(strings.Join(s, ", "))
}

输出结果:

foo, bar, baz

阅读上面这段代码,我们使用 func Join(elems []string, sep string) string 将字符串切片中的所有元素,以 sep 为分隔符,拼接为字符串。

04 

字符串拼接

关于字符串拼接,分为编译时字符串拼接,和运行时字符串拼接。

其中,编译时字符串拼接,即使用 + 将多个字符串拼接为一个字符串,需要注意的是,在使用 + 拼接字符串时,如果存在字符串变量,则会在运行时拼接。

示例代码:

func main() {
    str := "hello" + " world"
    fmt.Println(str)
    name := "frank"
    outPut := "My name is " + name
    fmt.Println(outPut)
}

输出结果:

hello world
My name is frank

阅读上面这段代码,第一个字符串拼接是在编译时拼接,第二个字符串拼接是在运行时拼接。

需要注意的是,运行时拼接是分配一块新的内存空间,通过内存拷贝的方式将字符串拷贝到新内存空间。

如果拼接后的字符串小于 32 字节,可以使用临时缓存;如果拼接后的字符串大于 32 字节,需要在堆区分配一块内存空间,并将需要拼接的多个字符串通过内存拷贝的形式拷贝过去。

字符串与字节数组互相转换时,也需要通过内存拷贝的方式,如果字符串大于 32 字节,需要在堆区分配一块内存空间,所以在一些转换密集的场景,我们需要特别注意。

此外,除了使用操作符 + 或 += 拼接字符串之外,还有多种字符串拼接方式,例如,fmt.Sprintfbytes.Bufferstrings.Join 和 stings.Builder。这些字符串拼接方式在之前的文章 「Golang 语言怎么高效拼接字符串?」 介绍过,本文不再赘述。

05 

总结

本文我们介绍 Go 语言中字符串的使用方式,包括类型转换、字符串操作、字符串拼接。

除了使用标准库 strconv 进行字符串类型转换之外,读者朋友们也可以选择三方库,例如:github.com/spf13/cast

建议读者朋友们阅读标准库文档,了解更多关于标准库 strconv 和 strings 的函数。

推荐阅读

  1. Prometheus Go client library 详解
  2. Golang 语言怎么高效使用字符串?
  3. Golang 语言怎么高效拼接字符串?
  4. Golang 语言怎么高效读写 JSON 字符串?
  5. Go 语言怎么使用类型转换和类型断言?

图片

扫描二维码或回复「微信群」,加入微信群

图片

点「赞」和「在看」是最大的支持?

图片

?更多精彩内容,请点击阅读原文」

收录于合集 #Golang语言
 156
上一篇Prometheus 的查询语言 PromQL 详解
阅读原文
阅读 568
Golang语言开发栈