Fork me on GitHub

Go语言开发-字符串-字符和字符串

3.3.字符和字符串

在Go语言中,字符有两种不同的表示方式(可以很容易地互相转换)。单个字符可以用一个rune(或者int32)来表示。从现在开始,我们交替使用术语“字符”、“码点”、“Unicode字符”、“Unicode码点”来表示包含一个字符的rune(或者int32)。Go语言的字符串被表示成一个包含0个或多个字符且每个字符由一个或多个UTF-8编码的字节表示的序列。

我们可以使用Go语言标准转换语法(string(char))将一个字符转换成一个只包含一个字符的字符串。参见下面的例子。

这段程序会打印出一行包含6个重复的“[0xE6 ‘æ’]”的行。最后,字符串æs将包含文本ææææææ。(接下来我们将通过在循环中使用字符串的+=操作符来让程序运行更高效。)

可以使用chars:=[]rune(s) 语法将一个字符串转换成一个rune(即码点)切片,其中s是字符串类型的,chars是[]int32类型的,因为rune和int32是同物异名。这在当我们需要逐字符解析字符串且同时需要查看当前字符的前一个或后一个字符时非常有用。使用s:=string(chars)语法进行逆向转换也同样简单,其中chars是[]rune或[]int32类型的,s是字符串类型的。这两种转换并不是毫无限制的,但它们的转换速度还是比较快的(时间复杂度为O(n))。更多关于字符串的转换请参见表3.2,。关于数字↔字符串的转换请参见表3.8和表3.9。

虽然方便,但是在一个循环中使用字符串的+=操作符追加字符串并不是最有效的方式。更好的方式(python程序员可能非常熟悉)是将字符串填充到一个字符串切片([]string)中,然后使用strings.Join()函数将切片中所有字符串连接起来。对于Go语言来说,有一种更好的方法,其个工作原理类似于Java中的StringBuilder。请看下面的例子。

我们首先创建一个空的bytes.Buffer缓冲区。然后我们使用bytes.Buffer.WriteString()方法将需要连接的每个字符串写入到这个缓冲区中。(当然,如果需要,我们可以在每个字符串中添加分隔符。)最后,使用bytes.Buffer.String()方法得到整个连接后的字符串。

将bytes.Buffer中的字符串连接起来可能比使用+=操作符具有更高的内存和CPU使用效率,尤其是在要连接的字符串数量很大时。

Go语言的for … range循环可以被用于逐字符的遍历字符串,并在每次遍历时产生一个位置索引和一个码点。请参见下面的例子。

大O表示法

大O表示法,O(…),被用于在复杂性理论中为特定算法中使用的处理时间和内存消耗给出一个近似边界。大多数是以要处理的项的数量或项的长度n的比例作为测量方法。可以使用它们来测量内存消耗或处理时间。

O(1)是指常量时间,也就是说,这是最快的可能而不论n有多大。O (logn) 是指对数时间;速度非常快且与log n成比例。O(n) 是指线性时间;速度较快且与n成比例。O( )是指平方时间;速度开始减慢且与 成比例。O( ) 是指多项式时间;随着n的增长很快减慢,特别是当 m ≥ 3时。O(n!) 是指阶乘的时间;即使n的值很小,这也会变得非常慢以至于无法在实际项目中使用。

本书在有些地方使用大O表示法来让读者对程序执行时的所消耗的资源成本有一个清晰的感受,例如,将一个字符串转换为一个 []runed的代价。

我们创建了一个phrase字符串常量,然后我们在下一行将其打印出来。再然后我们遍历字符串中的每个字符,Go语言的for…range循环在遍历字符串时将UTF-8字节解码成Unicode码点(rune),所以我们不必关心其底层实现。对于每个字符,我们将其索引位置、码点值(使用Unicode表示法),它表示的字符和用于编码字符的UTF-8字节打印出来。

我们通过将码点(rune类型的字符)转换成字符串(将包含一个由一个或多个UTF-8编码的字节组成的字符)来得到一个字节列表。然后,我们将该仅有一个字符的字符串转换成一个[]byte切片,即字节切片,以便可以访问其真实的字节。[]byte(string)转换速度是非常快(O(1))的,因为在底层[]byte可以简单地引用字符串的底层字节而无需复制。同样,逆向转换string([]byte)也是如此,其底层字节也无需复制,所以其转换复杂度也是0(1)。表3.2列出了Go语言的字符串与字节的转换关系。

%-2d、%U、 %c、和 %X格式化说明符会稍后解释。接下来我们将会看到,当%X格式化说明符被用于数字时,它以十六进制的形式输出该数字,当其被用于[]byte时,它输出一个两位十六进制数字的序列,一个数字代表一个字节。这里我们通过在格式说明符中加入空格来输出以空格分隔的字节。

在实际编程中通过与strings和fmt包(也可能来自于strconv、unicode和unicode/utf8包)中的函数一起,使用for…range循环来遍历字符串中的字符,这些函数提供了编程所需的强大且方便的字符串处理和操作功能。然而,此外,字符串类型还支持切片(因为在底层一个字符串实际上就是一个增强的[]byte切片),这是非常有用的,如果我们足够小心而不将一个多字节的字符切片截断。


目录


作者:Johnson
原创文章,版权所有,转载请保留原文链接。

发表评论

电子邮件地址不会被公开。 必填项已用*标注