Golang 入门 : 字符串
在 Golang 中,字符串是一种基本类型,这一点和 C 语言不同。C 语言没有原生的字符串类型,而是使用字符数组来表示字符串,并以字符指针来传递字符串。Golang 中的字符串是一个不可改变的 UTF-8 字符序列,一个 ASCII 码占用 1个字节,其它字符根据需要占用 2-4 个字节,这一点与其它主流的开发语言( C++、Java、Python)是不同的。这样设计的好处有两个:
- 减少内存的使用,节约硬盘空间
- 统一编码格式(UTF-8)有助于减少读取文件时的编码和解码工作
字符串的声明与初始化
声明和初始化字符串非常容易:
s := "hello world"
上面的代码声明了字符串变量 s,其内容为 "hello world"。在 Golang 中字符串的值是不可变的,当创建一个字符串后,无法再次修改这个字符串的内容。所以如果你通过下面的代码修改 s 中的内容就会发生编译错误:
s := "hello nick"
字符串字面量
Golang 支持两种类型的字符串字面量:
- 解释型字符串
- 非解释型字符串
所谓的解释型字符串就是用双引号括起来的字符串(""),其中的转义字符会被替换掉,这些转义字符包括:
\a // 响铃
\b // 退格
\f // 换页
\n // 换行
\r // 回车
\t // 制表符
\u // Unicode 字符
\v // 垂直制表符
\" // 双引号
\\ // 反斜杠
非解释型字符串是指用反引号( ` 一般在 Esc 键下面,数字键 1 的左边)括起来的字符串。在非解释型字符串中的转义字符不会被解释,并且还支持换行。
看下面的 demo:
package main
import "fmt" func main() {
s1 := "Hello\nWorld!"
s2 := `Hello\n
nick!`
fmt.Println(s1)
fmt.Println(s2)
}
运行上面的代码,输出如下:
反单引号可以跨行,并且引号内的所有内容都会直接输出,包括转义字符和空格缩进等。而双引号则不能换行,并且会解析转义字符。
字符串的长度
内置函数 len() 可以返回一个字符串中的字节数(注意,不是 rune 字符数目),索引操作 s[i] 可以返回字符串 s 中第 i 个字节的值。
s := "abc你"
fmt.Printf("字符串的字节长度是:%d\n", len(s))
for i := ; i < len(s); i++ {
fmt.Println(s[i])
}
字符串的字节长度是:6
// a
// b
// c
// 你
// 你
// 你
最后的三个字节组成了汉字 "你"。
如果要获取字符串中字符的个数,可以先把字符串转换成 []rune 类型,然后用 len() 函数获取字符个数:
s := "abc你"
r := []rune(s)
fmt.Print(len(r))
这次输出的结果为:4。
从字符串中截取内容
可以通过下面的语法截取字符串中的内容:
s := "abcdef"
s1 := s[:]
此时 s1 的内容为 "bcd",该语法通过下标索引的方式截取字符串中的内容,特点是 "左含右不含"。也就是说新的子串包含源串索引为 1 的字符,而不包含源串索引为 4 的字符。
如果要从源串的开始处截取可以省略第一个索引:
s2 := s[:]
s2 的内容为 "abcd"。
如果要从源串的某个位置开始一直截取到末尾,可以省略第二个索引:
s3 := s[:]
s3 的内容为 "cdef"。
访问越界问题
在通过索引访问字符串或者是截取子串时需要考虑索引越界的问题,如果试图访问超出字符串索引范围的字节将会在运行时导致 panic 异常:
s4 := s[:]
连接字符串
使用 + 号可轻松的把字符串连接起来:
s := "hello"
s1 := " "
s2 := "world"
s3 := s + s1 + s2
此时 s3 的内容为 "hello world"。
遍历字符串
由于可以通过下标索引字符串中的字节,所以可以用这种方式遍历字符串:
s := "abc你好"
for i := ; i < len(s); i++ {
fmt.Printf("%c", s[i])
}
输出的结果如下:
abcä½ å¥½
可见在字符串中含有非单字节的字符时这种方法是不正确的。range 函数能解决这个问题:
for _, v := range s {
fmt.Printf("%c", v)
}
这次输出的结果为:
abc你好
修改字符串
在 Golang 中,不能修改字符串的内容,也就是说不能通过 s[i] 这种方式修改字符串中的字符。要修改字符串的内容,可以先将字符串的内容复制到一个可写的变量中,一般是 []byte 或 []rune 类型的变量,然后再进行修改。
如果要对字符串中的字节进行修改,就转换为 []byte 类型,如果要对字符串中的字符修改,就转换为 []rune 类型,在转换类型的过程中会自动复制数据。
修改字符串中的字节(用 []byte)
对于那些单字节字符来说,可以通过这种方式进行修改:
s := "Hello 世界"
b := []byte(s) // 转换为 []byte,数据被自动复制
b[] = ',' // 把空格改为半角逗号
fmt.Printf("%s\n", s)
fmt.Printf("%s\n", b)
输出结果为:
Hello 世界
Hello,世界
修改字符串中的字符(用 []rune)
s := "Hello 世界"
b := []rune(s) // 转换为 []rune,数据被自动复制
b[] = '中'
b[] = '国'
fmt.Println(s)
fmt.Println(string(b))
输出结果为:
Hello 世界
Hello 中国
注意:和 C/C++ 不一样,Golang 语言中的字符串是根据长度限定的,而非特殊的字符 \0。string 类型的 0 值是长度为 0 的字符串,即空字符串 ""。
strings 包
strings 是非常重要的一种基本类型,所需要执行的操作繁多且比较复杂,因此一般的编程语言都会额外封装一些方法用于处理字符串。Golang 语言的标准库中也存在这样一个名称为 strings 的库。下面介绍一些 strings 库的常见用法。
检查是否包含子串
判断一个字符串中是否包含某个子串是经常遇到的一种字符串操作,在 strings 包中,可以使用 Contains() 函数进行判断:
s := "A good tree bears good fruit"
fmt.Printf("%t\n", strings.Contains(s, "tree"))
输出的结果为:true。
如果要检查字符串是不是以某个子串开始的,可以使用 HasPrefix() 函数:
s := "A good tree bears good fruit"
fmt.Printf("%t\n", strings.HasPrefix(s, "A good"))
输出的结果为:true。
如果要检查字符串是不是以某个子串结束的,可以使用 HasSuffix() 函数:
s := "A good tree bears good fruit"
fmt.Printf("%t\n", strings.HasSuffix(s, "good fruit"))
输出的结果为:true。
与 Contains() 函数相比,ContainsAny() 函数能够匹配更广泛的内容,并且可以匹配 Unicode 字符:
fmt.Println(strings.Contains("failure", "a & o")) // false
fmt.Println(strings.Contains("foo", "")) // true
fmt.Println(strings.Contains("", "")) // true fmt.Println(strings.ContainsAny("failure", "a & o")) // true
fmt.Println(strings.ContainsAny("foo", "")) // false
fmt.Println(strings.ContainsAny("", "")) // false fmt.Println(strings.ContainsAny("好树结好果", "好树")) // true
获取子串的索引
在 Golang 中,字符串中的字符都有一个索引值,很多时候我们要操作字符串,就必须先获取字符在字符串中的索引值。在 strings 包中 Index 函数可以返回指定字符或字符串的第一个字符的索引值,如果不存在则返回 -1:
fmt.Println(strings.Index("Hi I'm Nick, Hi", "Nick")) //
fmt.Println(strings.Index("Hi I'm Nick, Hi", "Hi")) //
fmt.Println(strings.Index("Hi I'm Nick, Hi", "abc")) // -1
fmt.Println(strings.LastIndex("Hi I'm Nick, Hi", "Hi")) //
LastIndex 函数返回匹配到的最后一个子串的索引值。
如果处理包含多个字节组成的字符的字符串,需要使用 IndexRune 函数来对字符进行定位:
fmt.Println(strings.IndexRune("好树结好果", '树')) //
注意这里返回的是 3,这是 "树" 的第一个字节在字符串中的位置。
替换字符串
替换字符串最常用的方式其实是通过正则匹配去替换的,其灵活度更高。而 Golang 则为比较基础的替换操作提供了 Replace 函数:
fmt.Println(strings.Replace("你好世界", "世界", "地球", ))
输出的结果为:你好地球
strings.Replate(str, old, new, n) 函数一共有 4 个参数,第一个为源字符串,第二个表示源字符串中需要被替换掉的字符串,第三个是替换的内容,最后一个 n 则表示替换匹配到的前 n 个记录。
大小写转换
操作字符串就免不了大小写转换,ToLower() 函数把字符串转换为小写,ToUpper() 函数把字符串转换为大写:
s := "A good tree bears good fruit"
s1 := "HOW ARE YOU?"
fmt.Printf("%s\n", strings.ToUpper(s))
fmt.Printf("%s\n", strings.ToLower(s1))
输出的结果如下:
A GOOD TREE BEARS GOOD FRUIT
how are you?
修剪
在处理用户的输入时,去掉字符串前后多余的空白字符非常重要,strings 包中提供了 Trem()、TrimLeft() 和 TrimRight() 来实现这个功能:
fmt.Printf("%q\n", strings.Trim(" Golang ", " "))
fmt.Printf("%q\n", strings.TrimLeft(" Golang ", " "))
fmt.Printf("%q\n", strings.TrimRight(" Golang ", " "))
输出的结果如下:
"Golang"
"Golang "
" Golang"
分隔与拼接
Split() 函数按照指定的分隔符分隔字符串并返回一个切片:
fmt.Printf("%q\n", strings.Split("a,b,c", ","))
fmt.Printf("%q\n", strings.Split("a boy a girl a cat", "a "))
fmt.Printf("%q\n", strings.Split("xyz", ""))
输出的结果如下:
["a" "b" "c"]
["" "boy " "girl " "cat"]
["x" "y" "z"]
Join() 函数则会将元素类型为 string 的切片使用分隔符拼接组成一个字符串:
fmt.Printf("%q\n", strings.Join([]string{"boy", "girl", "cat"}, ";"))
输出的结果如下:
"boy;girl;cat"
strconv 包
这个包主要用于字符串与其他类型的转换。这里我们简单的看下如何通过 Itoa() 函数把字符串转换为整型:
num, _ := strconv.Atoi("")
num +=
fmt.Printf("%d\n", num)
上面这段代码输出的结果为:128
这说明字符串 "123" 被成功的转换成了十进制整数 123,随后还进行了加法运算。
总结
对于任何一门编程语言来说,字符串的定义和相关操作都是非常基础的内容。从本文我们可以看到,Golang 的字符串类型原生支持 Unicode,操作起来也非常的方便,特别是提供了便利的 strings 包。这让我们能够轻松的了解并使用 Golang 的 string 类型。
参考:
《Go语言编程入门与实战技巧》
Golang 入门 : 字符串的更多相关文章
- Java程序员的Golang入门指南(上)
Java程序员的Golang入门指南 1.序言 Golang作为一门出身名门望族的编程语言新星,像豆瓣的Redis平台Codis.类Evernote的云笔记leanote等. 1.1 为什么要学习 如 ...
- Java程序员的Golang入门指南(下)
Java程序员的Golang入门指南(下) 4.高级特性 上面介绍的只是Golang的基本语法和特性,尽管像控制语句的条件不用圆括号.函数多返回值.switch-case默认break.函数闭包.集合 ...
- golang的字符串拼接
常用拼接方法 字符串拼接在日常开发中是很常见的需求,目前有两种普遍做法: 一种是直接用 += 来拼接 s1 := "Hello" s2 := "World" s ...
- 【Golang】字符串首字母大小写转化
写在前面 在自动化过程中,我们用得最多的可能就是字符串的处理,熟悉Python的都知道在Python中要让一个字符串的首字母大写直接用capitalize就可以了,但是同样的事情在Golang中没有这 ...
- Golang 入门 : 竞争条件
笔者在前文<Golang 入门 : 理解并发与并行>和<Golang 入门 : goroutine(协程)>中介绍了 Golang 对并发的原生支持以及 goroutine 的 ...
- Golang 入门 : goroutine(协程)
在操作系统中,执行体是个抽象的概念.与之对应的实体有进程.线程以及协程(coroutine).协程也叫轻量级的线程,与传统的进程和线程相比,协程的最大特点是 "轻"!可以轻松创建上 ...
- Golang - 处理字符串
目录 Golang - 处理字符串 1. 字符串操作 2. 字符串转换 Golang - 处理字符串 1. 字符串操作 func Contains(s, substr string) bool 字符串 ...
- Golang 入门 : channel(通道)
笔者在<Golang 入门 : 竞争条件>一文中介绍了 Golang 并发编程中需要面对的竞争条件.本文我们就介绍如何使用 Golang 提供的 channel(通道) 消除竞争条件. C ...
- 推荐一个GOLANG入门很好的网址
推荐一个GOLANG入门很好的网址,栗子很全 https://books.studygolang.com/gobyexample/
随机推荐
- Ruby Enumerator的各种迭代
Enumerator迭代 Mix-in Enumerator获得的迭代方法: each_cons: each_slice: each_with_index: with_index: each_with ...
- 为你的Python程序加密
在实际的工作中,有时候我们需要部署自己的Python应用,但这时候我们并不希望别人能够看到自己的Python源程序.因此,我们需要为自己的源代码进行加密,Python已经为我们提供了这样一套工作机 ...
- ----Juquery复选框全选反选及获取选中值Value
--获取选中值 var pList = ""; $("[name='ckdProd']").each(function () { if ($(this).is( ...
- nodejs 动态创建二维码
<!--弹出二维码--> <div class="qrcode"> <div> <p id="saoma">扫描 ...
- 经典面试题:浏览器是怎样解析CSS的?
摘要: 理解浏览器原理. 解析 一旦 CSS 被浏览器下载,CSS 解析器就会被打开来处理它遇到的任何 CSS.这可以是单个文档内的 CSS.<style>标记内的 CSS,也可以是 DO ...
- 过滤器(Filter)和拦截器(Interceptor)
过滤器(Filter) Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序.它依赖于servlet容器,在实现上,基于函数回调,它可以对几乎所有请求 ...
- 浅谈Semaphore类
Semaphore类有两个重要方法 1.semaphore.acquire(); 请求一个信号量,这时候信号量个数-1,当减少到0的时候,下一次acquire不会再执行,只有当执行一个release( ...
- java基础中this,super
this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针. super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类. this的用法就不累赘的说 ...
- idea部署Maven入门(一)——环境变量的配置和下载
介绍: 1 Maven是用来管理jar包的一种工具, 2 Maven主要是构建java项目和java web项目 3 maven项目管理所依赖的jar ...
- 两种常用的全排列算法(java)
问题:给出一个字符串,输出所有可能的排列. 全排列有多种算法,此处仅介绍常用的两种:字典序法和递归法. 1.字典序法: 如何计算字符串的下一个排列了?来考虑"926520"这个字符 ...