go系列教程-字符串
1、什么是字符串?
Go语言中字符串是一个字节切片。把内容放在双引号""之间,我们可以创建一个字符串,让我们来看一下创建并打印字符串的简单示例。
package main import ( "fmt" ) func main() { str := "hello golang" fmt.Println(str) }
在线运行程序
hello golang
2、获取字符串的每一个字节
由于字符串是一个字节切片,所以我们可以获取字符串的每一个字节
package main import ( "fmt" ) func main() { str := "hello golang" printChars(str) fmt.Println() printBytes(str) fmt.Println() printCharsAndBytes(str) } // 字节 %x 限定打印字符串字节 func printBytes(s string) { for i := 0; i < len(s); i++ { fmt.Printf("%x ", s[i]) } } // 字符 %c 限定打印字符串的字符 func printChars(s string) { for i := 0; i < len(s); i++ { fmt.Printf("%c ", s[i]) } } // for range 循环是最简单方法方 func printCharsAndBytes(s string) { for _, rune := range s { fmt.Printf("%c starts at byte %x\n", rune, rune) } }
在线运行程序
h e l l o g o l a n g 68 65 6c 6c 6f 20 67 6f 6c 61 6e 67 h starts at byte 0 e starts at byte 1 l starts at byte 2 l starts at byte 3 o starts at byte 4 starts at byte 5 g starts at byte 6 o starts at byte 7 l starts at byte 8 a starts at byte 9 n starts at byte a g starts at byte b airdeMacBook-Air:learn_demo wutianxiang$ go run main.go h e l l o g o l a n g 68 65 6c 6c 6f 20 67 6f 6c 61 6e 67 h starts at byte 68 e starts at byte 65 l starts at byte 6c l starts at byte 6c o starts at byte 6f starts at byte 20 g starts at byte 67 o starts at byte 6f l starts at byte 6c a starts at byte 61 n starts at byte 6e g starts at byte 67
如果我们再上面基础上字符串含中文,那会如何?
package main import ( "fmt" ) func main() { str := "hello golang 语言" printChars(str) fmt.Println() printBytes(str) fmt.Println() printCharsAndBytes(str) } // 字节 %x 限定打印字符串字节 func printBytes(s string) { for i := 0; i < len(s); i++ { fmt.Printf("%x ", s[i]) } } // 字符 %c 限定打印字符串的字符 func printChars(s string) { for i := 0; i < len(s); i++ { fmt.Printf("%c ", s[i]) } } // for range 循环是最简单方法方 func printCharsAndBytes(s string) { for _, rune := range s { fmt.Printf("%c starts at byte %x\n", rune, rune) } }
在线运行程序
h e l l o g o l a n g è ¯ è ¨ 68 65 6c 6c 6f 20 67 6f 6c 61 6e 67 20 e8 af ad e8 a8 80 h starts at byte 68 e starts at byte 65 l starts at byte 6c l starts at byte 6c o starts at byte 6f starts at byte 20 g starts at byte 67 o starts at byte 6f l starts at byte 6c a starts at byte 61 n starts at byte 6e g starts at byte 67 starts at byte 20 语 starts at byte 8bed 言 starts at byte 8a00
上面第一行输出了错误 h e l l o g o l a n g è ¯ è ¨
为什么程序分割 hello golang 时表现完美,但分割字符含中文就错误?
这是“语言”的unicode代码点(code point)是U+00F1。他的UTF-8编码占用了 e8 af ad e8 a8 80
6个字节。
它的UTF-8编码占用了8个字节 e8 af ad e8 a8 80。而我们打印字符时,却假定每个字符的编码只会占用一个字节,这是错误的。
在UTF-8编码中,一个代码点可能会占用超过一个字节的空间。
那么我们该怎么办呢?
rune 能帮我们解决这个难题。
rune是Go语言的内建类型,它是int32的别称。在Go语言中,rune表示一个代码点,无论代码点占用多少个字节,都可以用一个rune来表示。
package main import ( "fmt" ) func main() { str := "hello golang 语言" printChars(str) fmt.Println() printBytes(str) fmt.Println() printCharsAndBytes(str) } // 字节 %x 限定打印字符串字节 func printBytes(s string) { for i := 0; i < len(s); i++ { fmt.Printf("%x ", s[i]) } } // 字符 %c 限定打印字符串的字符 func printChars(s string) { runes := []rune(s) for i := 0; i < len(runes); i++ { fmt.Printf("%c ", runes[i]) } } // for range 循环是最简单方法方 func printCharsAndBytes(s string) { for _, rune := range s { fmt.Printf("%c starts at byte %x\n", rune, rune) } }
在线运行程序
h e l l o g o l a n g 语 言 68 65 6c 6c 6f 20 67 6f 6c 61 6e 67 20 e8 af ad e8 a8 80 h starts at byte 68 e starts at byte 65 l starts at byte 6c l starts at byte 6c o starts at byte 6f starts at byte 20 g starts at byte 67 o starts at byte 6f l starts at byte 6c a starts at byte 61 n starts at byte 6e g starts at byte 67 starts at byte 20 语 starts at byte 8bed 言 starts at byte 8a00
3、用字节切片构造字符串
package main import ( "fmt" ) func main() { // 十六进制 byteSlice := []byte{0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x67, 0x6F, 0x6C, 0x61, 0x6E, 0x67, 0x20, 0xE8, 0xAF, 0xAD, 0xE8, 0xA8, 0x80} str := string(byteSlice) fmt.Println(str) }
在线运行程序
hello golang 语言
4、rune 切片构造字符串
package main import ( "fmt" ) func main() { runeSlice := []rune{104, 101, 108, 108, 111, 32, 103, 111, 108, 97, 110, 103, 32, 35821, 35328} str := string(runeSlice) fmt.Println(str) }
在线运行程序
hello golang 语言
5、获取字符串长度
对于字母数字组合成字符串获取长度,用len()方法;
对于中文或其它国家文字组成字符串获取长度,用utf8.RuneCountInString()方法
package main import ( "fmt" "unicode/utf8" ) func main() { str1 := "hello" length(str1) str2 := "hello您好" length(str2) } // 获取字符串长度 func length(s string) { fmt.Printf("length of %s is %d\n", s, utf8.RuneCountInString(s)) }
6、字符串是不可变的。一旦创建一个字符串,那么他将无法被修改。如果试图把字符串修改,程序会抛出一个错误:cannot assign to s[0]
package main import ( "fmt" ) func main() { str := "hello" fmt.Println(midfyString(str)) } // 修改字符串 func midfyString(s string) string { s[0] = 'a' return s }
上面这个操作是非法的。
那么如果修改字符,可以把字符串转化一个rune切片,然后对这个切片任何修改,再将转化一个新的字符串
package main import ( "fmt" ) func main() { str := "hello" fmt.Println(midfyString(str)) fmt.Println(str) } // 修改字符串 func midfyString(s string) string { runes := []rune(s) // 注意这个是单引号。如果改成双引号,可以试试发生什么 runes[0] = 'a' return string(runes) }
7、字符串拼接,后续。。