Golang 字符串操作汇总
- 1 string初始化
- 2 遍历string
- 3 byte & Rune
-
- 4 字符串拼接
-
- 4.1 +号
- 4.2 sprintf函数
- 4.3 strings包里的Join函数
- 4.4 bytes包里的buffer.Builderbuffer.WriteString函数
- 4.5 strings包里的buffer.Builder函数
- 主要结论
- 5 字符串格式化
-
- 5.1 fmt
- 5.2 fmt.Sprintf语法
- 5.3 格式化列表
-
- 5.3.1 整数格式化
- 5.3.2 浮点数格式化
- 5.3.3 布尔类型格式化
- 5.3.4 字符格式化
- 5.3.5 字符串格式化
- 5.3.6 指针格式化
- 5.3.7 通用占位符
- 5.4 宽度表示
-
- 5.4.1 浮点数精度控制
- 5.4.2 字符串长度控制
1 string初始化
func newString() {
str := "one hello \n world"
fmt.Println(str)
str1 := `two hello \n world`
str2 := `h1
h2
h3`
fmt.Println(str1)
fmt.Println(str2)
var str3 string
str3 = "three hello world"
fmt.Println(str3)
fmt.Println("------------------")
}
2 遍历string
func forString() {
for index, s := range "abcdef" {
fmt.Printf("%c 索引值是 %d\n", s, index)
}
str := "Hello"
for c := 0; c < len(str); c++ {
fmt.Printf("\n字符 = %c 字节 = %v", str[c], str[c])
}
fmt.Println()
fmt.Println("------------------")
}
3 byte & Rune
3.1 初始化
func byteAndRune() {
myslice1 := []byte{72, 101, 108, 108, 111}
mystring1 := string(myslice1)
fmt.Println("String 1: ", mystring1)
fmt.Println("------------------")
myslice2 := []rune{0x47, 0x65, 0x65, 0x6b, 0x73}
mystring2 := string(myslice2)
fmt.Println("String 2: ", mystring2)
fmt.Println("------------------")
}
3.2 byte和rune区别
- rune是用来区分字符值和整数值的
- rune 等同于int32,即4个字节长度,常用来处理unicode或utf-8字符。
- byte 等同于int8,即一个字节长度,常用来处理ascii字符
- 中文字符在unicode下占2个字节,在utf-8编码下占3个字节,而golang默认编码正好是utf-8。
- ASCII编码是1个字节,而UTF-8是可变长的编码
- 当要表示中文等非ASCll编码的字符时,需要使用UTF-8编码来保证不会乱码。
- UTF8编码下一个中文汉字由3~4个字节组成,而字符串是由byte字节组成,所以长度也是byte字符长度,这样遍历时遇到中文就乱码了
- 所谓对字符串的修改其实不是对字符串本身的修改,而是复制字符串,同时修改值,即重新分配来内存。
- 在go中修改字符串,需要先将字符串转化成数组,[]byte 或 []rune,然后再转换成 string型。
func byteAndRune() {
str := "你好 world"
fmt.Printf("len(str):%d\n", len(str))
fmt.Printf("len(byte(str)):%d\n", len([]byte(str)))
fmt.Printf("len(rune(str)):%d\n", len([]rune(str)))
for i := 0; i < len(str); i++ {
fmt.Printf("%c", str[i])
}
fmt.Println()
for _, value := range str {
fmt.Printf("%c", value)
}
fmt.Println()
str1 := "abc"
s1 := []byte(str1)
s1[0] = 'b'
fmt.Println(string(s1))
str2 := "你好,世界"
s2 := []rune(str2)
s2[0] = '不'
fmt.Println(string(s2))
}
4 字符串拼接
4.1 +号
func main() {
s1 := "hello"
s2 := "word"
s3 := s1 + s2
fmt.Print(s3)
}
go语言用+拼接,不过由于golang中的字符串是不可变的类型,因此用 + 连接会产生一个新的字符串对效率有影响。
4.2 sprintf函数
func main() {
s1 := "hello"
s2 := "word"
s3 := fmt.Sprintf("%s%s", s1, s2)
fmt.Println(s3)
}
4.3 strings包里的Join函数
Join函数会先根据字符串数组的内容,计算出一个拼接之后的长度,然后申请对应大小的内存,一个一个字符串填入,在已有一个数组的情况下,这种效率会很高,如果没有的话效率也不高。还可以用来切片转字符串
func main() {
s1 := "hello"
s2 := "word"
var str []string = []string{s1, s2}
s3 := strings.Join(str, "")
fmt.Print(s3)
}
4.4 bytes包里的buffer.Builderbuffer.WriteString函数
s1 := "hello"
s2 := "word"
var bt bytes.Buffer
bt.WriteString(s1)
bt.WriteString(s2)
s3 := bt.String()
fmt.Println(s3)
4.5 strings包里的buffer.Builder函数
s1 := "hello"
s2 := "word"
var build strings.Builder
build.WriteString(s1)
build.WriteString(s2)
s3 := build.String()
fmt.Println(s3)
主要结论
- 后三种性能高
- 在已有字符串数组的场合,使用 strings.Join() 能有比较好的性能
- 如果需要拼接的不仅仅是字符串,还有数字之类的其他需求的话,可以考虑 fmt.Sprintf()
5 字符串格式化
5.1 fmt
Go语言用于控制文本输出常用的标准库是fmt
fmt中主要用于输出的函数有:
- Print: 输出到控制台,不接受任何格式化操作
- Println: 输出到控制台并换行
- Printf: 格式化输出,只可以打印出格式化的字符串,只可以直接输出字符串类型的变量(不可以直接输出别的类型)
- Sprintf: 格式化并返回一个字符串而不带任何输出
- Fprintf: 来格式化并输出到io.Writers而不是os.Stdout
5.2 fmt.Sprintf语法
fmt.Sprintf(格式化样式, 参数列表…)
- 格式样式: 字符串形式,格式化符号以%开头,%s字符串格式,%d十进制的整数格式
- 参数列表: 多个参数以逗号分隔,个数必须与格式化样式中的个数一一对应,否则运行时会报错
5.3 格式化列表
5.3.1 整数格式化
占 位 符 |
描 述 |
%b |
整数以二进制方式显示 |
%o |
整数以八进制方式显示 |
%d |
整数以十进制方式显示 |
%x |
整数以十六进制方式显示 |
%X |
整数以十六进制、字母大写方式显示 |
%c |
相应Unicode码点所表示的字符 |
%U |
Unicode字符,Unicode格式:123,等同于“U+007B” |
func main() {
fmt.Printf("%b \n", 123)
fmt.Printf("%o \n", 123)
fmt.Printf("%d \n", 123)
fmt.Printf("%x \n", 123)
fmt.Printf("%X \n", 123)
fmt.Printf("%c \n", 123)
fmt.Printf("%U \n", 123)
}
5.3.2 浮点数格式化
占 位 符 |
描 述 |
%e |
科学计数法,例如 1.234560e+02 |
%E |
科学计数法,例如 1.234560E+02 |
%f |
有小数点而无指数,例如 123.456 |
%F |
等价于%f |
%g |
根据情况选择 %e 或 %f 以产生更紧凑的(无末尾的0)输出 |
%G |
根据情况选择 %E 或 %F 以产生更紧凑的(无末尾的0)输出 |
func main() {
fmt.Printf("%e \n", 123.456)
fmt.Printf("%E \n", 123.456)
fmt.Printf("%f \n", 123.456)
fmt.Printf("%F \n", 123.456)
fmt.Printf("%g \n", 123.456)
fmt.Printf("%G \n", 123.456)
}
5.3.3 布尔类型格式化
占 位 符 |
描 述 |
%t |
true 或 false |
func main() {
fmt.Printf("%t", true)
}
5.3.4 字符格式化
占 位 符 |
描 述 |
%c |
相应Unicode码点所表示的字符 |
func main() {
fmt.Printf("%c", 0x4E2D)
}
5.3.5 字符串格式化
占 位 符 |
描 述 |
%s |
直接输出字符串或者[]byte |
%q |
双引号围绕的字符串,由Go语法安全地转义 |
%x |
每个字节用两字符十六进制数表示(使用a-f) |
%X |
每个字节用两字符十六进制数表示(使用A-F) |
func main() {
fmt.Printf("%s \n", "Hello world")
fmt.Printf("%q \n", "Hello world")
fmt.Printf("%x \n", "Hello world")
fmt.Printf("%X \n", "Hello world")
}
5.3.6 指针格式化
占 位 符 |
描 述 |
%p |
表示为十六进制,并加上前导的0x |
%#p |
表示为十六进制,没有前导的0x |
func main() {
a := "Hello world"
b := &a
fmt.Printf("%p \n", b)
fmt.Printf("%#p \n", b)
}
5.3.7 通用占位符
占 位 符 |
描 述 |
%v |
值的默认格式 |
%+v |
类似%v,但输出结构体时会添加字段名 |
%#v |
相应值的Go语法表示 |
%T |
相应值的类型的Go语法表示 |
%% |
百分号,字面上的%,非占位符含义 |
func main() {
fmt.Printf("%v \n", "Hello World")
type Student struct {
name string
age int
}
xiaoming := Student{name: "小明", age: 18}
fmt.Printf("%+v \n", xiaoming)
fmt.Printf("%#v \n", xiaoming)
fmt.Printf("%T \n", "Hello World")
fmt.Printf("%%%v \n", "Hello World")
}
5.4 宽度表示
5.4.1 浮点数精度控制
- 宽度通过一个紧跟在百分号后面的十进制数指定,如果未指定宽度,则表示值时除必需之外不作填充。
- 精度通过(可选的)宽度后跟点号后跟的十进制数指定。如果未指定精度,会使用默认精度;如果点号后没有跟数字,表示精度为0。
举例如下
func main() {
fmt.Printf("|%f|\n", 123.456)
fmt.Printf("|%12f|\n", 123.456)
fmt.Printf("|%.3f|\n", 123.456)
fmt.Printf("|%12.3f|\n", 123.456)
fmt.Printf("|%12.f|\n", 123.456)
}
5.4.2 字符串长度控制
- 宽度设置格式:占位符中间加一个数字, 数字分正负, +: 右对齐, -: 左对齐
- 最小宽度:百分号后紧跟十进制数,不够部分可以选择补0
- 最大宽度:小数点后的十进制数,超出的部分会被截断
func main() {
fmt.Printf("|%s|\n", "123.456")
fmt.Printf("|%12s|\n", "123.456")
fmt.Printf("|%-12s|\n", "123.456")
fmt.Printf("|%012s|\n", "123.456")
fmt.Printf("|%.5s|\n", "123.456")
}