如何在 Go (Golang) 中使用字符串

在编程术语中,字符串仅表示字符序列或字符数组。单个字符是一个字母数字值。早在 C 被发明的时代,计算机中的字符由 7 位 ASCII 码表示。因此,字符串是许多 7 位 ASCII 字符的集合。然而,随着世界范围内计算机使用的增长,7 位 ASCII 方案已不足以支持其他语言的字符。因此,提出了各种字符编码模型,例如 Unicode、UTF-8、UTF-16、UTF-32 等。Unicode FAQ是一个有趣的地方,可以获取更多关于这些的详细信息。

不同的编程语言有自己的字符编码方案。例如,Java 原生使用 UTF-16 在 16 位 UTF-16 代码单元序列和字节序列之间进行映射。另一方面,Go 使用 UTF-8。这两种都是多字节字符编码。UTF-8 最初是由设计 Go 的同一个人 Rob Pike 和 Ken Thompson 设计的。Go 字符串与 C 字符串有很大不同,并且不会在与 C 相同的低级别上运行。实际上,Go 字符串在更高级别上运行。与 C/C++ 和 Java 或 Python 中字符串是固定长度字符序列的常量类型不同,Go 字符串具有可变宽度,根据 UTF-8 编码方案,每个字符由一个或多个字节表示。尽管它们的行为类似于数组或字节片,

在这里,我们将讨论关于字符串类型及其在 Go 中的操作的几点。

Go 字符串函数

Golang 有一个内置的len函数,它返回字符串的长度或字符串的字节长度。根据数组方案,我们可以访问第i 个字节,其中 0<=i<=len(theString)。观察以下代码片段:

theString := "Love manifests in pleasing service"
fmt.Println(len(theString))

以下代码会导致恐慌,因为我们试图越界访问索引:

fmt.Println(theString[0], " ", theString[len(theString)]) //panic

相反,我们希望将上面的代码编写如下:

fmt.Println(theString[0], " ", theString[len(theString)-1]) // 76, 101 - (L, e)

在 Go 中有一个用于提取子字符串的简写。例如,我们可以这样写:

 
thestring[i:j] (where i<=j) 

生成一个新字符串,该字符串由从索引i开始到索引j-1的原始字符串的字节组成。该字符串将包含ji字节。以下结果是相同的输出,因为我们可以省略ij值,Go 分别假定它们为默认值0len(theString)

fmt.Println(theString[0:len(theString)]) // Love manifests in pleasing service
fmt.Println(theString[:len(theString)]) // Love manifests in pleasing service
fmt.Println(theString[0:]) // Love manifests in pleasing service
fmt.Println(theString[:]) // Love manifests in pleasing service

要提取子字符串,我们可以编写以下代码:

fmt.Println(theString[2:8]) // ve man
fmt.Println(theString[:8]) //Love man
fmt.Println(theString[6:]) //anifests in pleasing service

Go 字符串的不可变特性确保字符串值永远不会被更改,尽管我们可以分配一个新值——或连接一个新值——而不改变原始值。例如:

str1 :="sample text"
str2 := str1 // sample text
str1 += ", another sample" // sample text, another sample

但是如果我们尝试修改原始字符串值,它会标记一个编译时错误,因为它违反了 Go 字符串的不可变约束:

str1[4] = 'A' // 错误!

在 Go 中比较字符串

作为开发人员,我们经常需要比较两个字符串,Go 支持所有常见的比较运算符,包括==!=<><=>=。比较是逐字节进行的,并且在比较过程中遵循自然的词法顺序。这是一个如何在 Go 中比较两个字符串的简单示例:

str1 := "I saw a saw to saw"
str2 := "I saw" + " a saw to saw"

if str1 == str2 {
 fmt.Println("str1 == str2")
}
str2 += " a tree"
if str1 != str2 {
 fmt.Println("str1 != str2")
}
if str1 < str2 {
 fmt.Println("str1 < str2") } str1 += "Today " if str1 > str2 {
 fmt.Println("str1 > str2")
}

在 Go 中使用 strconv 包

在处理字符串时,我们经常需要将字符串类型转换为数值。strconv包包含许多将字符串值转换为表示许多基本 Go 数据类型的函数。例如,整数值可以从字符串表示形式转换如下:

strInt := "1234"
intVal, err := strconv.ParseInt(strInt, 10, 32) //1234, base-10 number and 32-bit
if err == nil {
 fmt.Println(intVal)
} else {
 fmt.Println(err)
}

strconv.ParseInt函数采用三个参数——解析的字符串值、基本类型和位大小。其他基本类型也有类似的函数,例如ParseFloatParseBoolParseUintParseComplex ,分别用于浮点、布尔值、无符号整数和复数值。

我们还可以在 Go 中将数值转换回字符串,如以下代码示例所示:

floatVal := 3.1415
strFloat = strconv.FormatFloat(floatVal, 'E', -1, 64)
fmt.Println(strFloat)

strconv提供的转换函数比FormalBoolFormatIntFormatUintFormatComplex等类似函数更通用。此外,在 Go 中将浮点值转换为字符串的一种快速方法是使用fmt包,如以下代码示例所示:

f := 2.5678
strFloat := fmt.Sprintf("%f", f)
fmt.Println(strFloat)

strconv包包含许多处理字符串值的转换函数。查看Go strconv 文档以获取更多详细信息

Go 中的字符串包

strings包是另一个用于字符串操作的实用程序包例如,这里我们有一个包含工作日作为数据的字符串,其中每个工作日由逗号 (,) 分隔。我们可以使用strings.Split函数解析字符串并提取每个工作日,如下所示:

str := "sun,mon,tue,wed,thu,fri,sat"
weekdays := strings.Split(str, ",")
for _, day := range weekdays {
 fmt.Println(day)
}

有许多这样的实用功能。例如,要将字符串转换为大写或小写字母,我们可以分别使用函数strings.ToUpper(str)strings.ToLower(str)。有诸如Trim之类的函数返回一个字符串切片,其中删除了切割集中的所有前导和尾随 Unicode 代码点。查看Go 字符串文档以获取更多详细信息。

Go 中的 unicode/utf8 包

unicode/utf8包包含许多用于查询和操作字符串和 UTF-8 字节的函数。它提供了在符文和 UTF-8 字节序列之间进行转换的功能。例如,utf8.DecodeRuneInString()utf8.DecodeLastRuneInString()返回字符串中的第一个和最后一个字符。这是一个简单的例子:

q := "A to Z"
fc, size1 := utf8.DecodeRuneInString(q)
fmt.Println(fc, size1)
lc, size2 := utf8.DecodeLastRuneInString(q)
fmt.Println(lc, size2)

查看Go utf8 文档以获取更多详细信息。

关于 Go 中字符串的最终想法

Go 为操作字符串提供了广泛的支持。还有其他包,如unicode ,提供查询 Unicode 代码点以确定它们是否满足特定条件的函数。regexp 包提供了使用正则表达式操作字符串的函数。关于 Go 字符串,需要理解的重要一点是,我们将字符串的各个元素松散地称为字符实际上是 UTF-8 字节序列,称为代码点,通常由单词 rune 表示,它是类型的别名整数 32。Go 包充满了字符串操作函数,这里我们只是触及了皮毛。请继续关注,我们将探索更多。

对其他 Go 功能感到好奇?查看我们关于Go 中反射的文章。