zoukankan      html  css  js  c++  java
  • 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    // 响铃     
        // 退格
    f    // 换页
    
        // 换行
    
        // 回车
    	    // 制表符
    u    // Unicode 字符
    v    // 垂直制表符
    "    // 双引号
    \    // 反斜杠

    非解释型字符串是指用反引号( ` 一般在 Esc 键下面,数字键 1 的左边)括起来的字符串。在非解释型字符串中的转义字符不会被解释,并且还支持换行。

    看下面的 demo:

    package main
    import "fmt"
    
    func main() {
        s1 := "Hello
    World!"
        s2 := `Hello
    
               nick!`
        fmt.Println(s1)
        fmt.Println(s2)
    }

    运行上面的代码,输出如下:

    反单引号可以跨行,并且引号内的所有内容都会直接输出,包括转义字符和空格缩进等。而双引号则不能换行,并且会解析转义字符。

    字符串的长度

    内置函数 len() 可以返回一个字符串中的字节数(注意,不是 rune 字符数目),索引操作 s[i] 可以返回字符串 s 中第 i 个字节的值。

    s := "abc你"
    fmt.Printf("字符串的字节长度是:%d
    ", len(s))
    for i := 0; i < len(s); i++ {
        fmt.Println(s[i])
    }

    字符串的字节长度是:6

    97         // a
    98         // b
    99         // c
    228        //
    189        //
    160        //

    最后的三个字节组成了汉字 "你"。

    如果要获取字符串中字符的个数,可以先把字符串转换成 []rune 类型,然后用 len() 函数获取字符个数:

    s := "abc你"
    r := []rune(s)
    fmt.Print(len(r))

    这次输出的结果为:4。

    从字符串中截取内容

    可以通过下面的语法截取字符串中的内容:

    s := "abcdef"
    s1 := s[1:4]

    此时 s1 的内容为 "bcd",该语法通过下标索引的方式截取字符串中的内容,特点是 "左含右不含"。也就是说新的子串包含源串索引为 1 的字符,而不包含源串索引为 4 的字符。
    如果要从源串的开始处截取可以省略第一个索引:

    s2 := s[:4]

    s2 的内容为 "abcd"。
    如果要从源串的某个位置开始一直截取到末尾,可以省略第二个索引:

    s3 := s[2:]

    s3 的内容为 "cdef"。

    访问越界问题
    在通过索引访问字符串或者是截取子串时需要考虑索引越界的问题,如果试图访问超出字符串索引范围的字节将会在运行时导致 panic 异常:

    s4 := s[2:10]

    连接字符串

    使用 + 号可轻松的把字符串连接起来:

    s := "hello"
    s1 := " "
    s2 := "world"
    s3 := s + s1 + s2

    此时 s3 的内容为 "hello world"。

    遍历字符串

    由于可以通过下标索引字符串中的字节,所以可以用这种方式遍历字符串:

    s := "abc你好"
    for i := 0; 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[5] = ','        // 把空格改为半角逗号
    fmt.Printf("%s
    ", s)
    fmt.Printf("%s
    ", b)

    输出结果为:
    Hello 世界
    Hello,世界

    修改字符串中的字符(用 []rune)

    s := "Hello 世界"
    b := []rune(s)    // 转换为 []rune,数据被自动复制
    b[6] = ''
    b[7] = ''
    fmt.Println(s)
    fmt.Println(string(b))

    输出结果为:
    Hello 世界
    Hello 中国

    注意:和 C/C++ 不一样,Golang 语言中的字符串是根据长度限定的,而非特殊的字符 。string 类型的 0 值是长度为 0 的字符串,即空字符串 ""。

    strings 包

    strings 是非常重要的一种基本类型,所需要执行的操作繁多且比较复杂,因此一般的编程语言都会额外封装一些方法用于处理字符串。Golang 语言的标准库中也存在这样一个名称为 strings 的库。下面介绍一些 strings 库的常见用法。

    检查是否包含子串
    判断一个字符串中是否包含某个子串是经常遇到的一种字符串操作,在 strings 包中,可以使用 Contains() 函数进行判断:

    s := "A good tree bears good fruit"
    fmt.Printf("%t
    ", strings.Contains(s, "tree"))

    输出的结果为:true。

    如果要检查字符串是不是以某个子串开始的,可以使用 HasPrefix() 函数:

    s := "A good tree bears good fruit"
    fmt.Printf("%t
    ", strings.HasPrefix(s, "A good"))

    输出的结果为:true。

    如果要检查字符串是不是以某个子串结束的,可以使用 HasSuffix() 函数:

    s := "A good tree bears good fruit"
    fmt.Printf("%t
    ", 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"))                // 7
    fmt.Println(strings.Index("Hi I'm Nick, Hi", "Hi"))                  // 0
    fmt.Println(strings.Index("Hi I'm Nick, Hi", "abc"))                 // -1
    fmt.Println(strings.LastIndex("Hi I'm Nick, Hi", "Hi"))              // 13

    LastIndex 函数返回匹配到的最后一个子串的索引值。
    如果处理包含多个字节组成的字符的字符串,需要使用 IndexRune 函数来对字符进行定位:

    fmt.Println(strings.IndexRune("好树结好果", ''))     // 3

    注意这里返回的是 3,这是 "树" 的第一个字节在字符串中的位置。

    替换字符串
    替换字符串最常用的方式其实是通过正则匹配去替换的,其灵活度更高。而 Golang 则为比较基础的替换操作提供了 Replace 函数:

    fmt.Println(strings.Replace("你好世界", "世界", "地球", 1))

    输出的结果为:你好地球
    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
    ", strings.ToUpper(s))
    fmt.Printf("%s
    ", strings.ToLower(s1))

    输出的结果如下:
    A GOOD TREE BEARS GOOD FRUIT
    how are you?

    修剪
    在处理用户的输入时,去掉字符串前后多余的空白字符非常重要,strings 包中提供了 Trem()、TrimLeft() 和 TrimRight() 来实现这个功能:

    fmt.Printf("%q
    ", strings.Trim(" Golang ", " "))
    fmt.Printf("%q
    ", strings.TrimLeft(" Golang ", " "))
    fmt.Printf("%q
    ", strings.TrimRight(" Golang ", " "))

    输出的结果如下:
    "Golang"
    "Golang "
    " Golang"

    分隔与拼接
    Split() 函数按照指定的分隔符分隔字符串并返回一个切片:

    fmt.Printf("%q
    ", strings.Split("a,b,c", ","))
    fmt.Printf("%q
    ", strings.Split("a boy a girl a cat", "a "))
    fmt.Printf("%q
    ", strings.Split("xyz", ""))

    输出的结果如下:
    ["a" "b" "c"]
    ["" "boy " "girl " "cat"]
    ["x" "y" "z"]

    Join() 函数则会将元素类型为 string 的切片使用分隔符拼接组成一个字符串:

    fmt.Printf("%q
    ", strings.Join([]string{"boy", "girl", "cat"}, ";"))

    输出的结果如下:
    "boy;girl;cat"

    strconv 包

    这个包主要用于字符串与其他类型的转换。这里我们简单的看下如何通过 Itoa() 函数把字符串转换为整型:

    num, _ := strconv.Atoi("123")
    num += 5
    fmt.Printf("%d
    ", num)

    上面这段代码输出的结果为:128
    这说明字符串 "123" 被成功的转换成了十进制整数 123,随后还进行了加法运算。

    总结

    对于任何一门编程语言来说,字符串的定义和相关操作都是非常基础的内容。从本文我们可以看到,Golang  的字符串类型原生支持 Unicode,操作起来也非常的方便,特别是提供了便利的 strings 包。这让我们能够轻松的了解并使用 Golang 的 string 类型。

    参考:
    《Go语言编程入门与实战技巧》

  • 相关阅读:
    LeetCode Missing Number (简单题)
    LeetCode Valid Anagram (简单题)
    LeetCode Single Number III (xor)
    LeetCode Best Time to Buy and Sell Stock II (简单题)
    LeetCode Move Zeroes (简单题)
    LeetCode Add Digits (规律题)
    DependencyProperty深入浅出
    SQL Server存储机制二
    WPF自定义RoutedEvent事件示例代码
    ViewModel命令ICommand对象定义
  • 原文地址:https://www.cnblogs.com/sparkdev/p/10666085.html
Copyright © 2011-2022 走看看