Golang -- 字节切片

xiaorenwuzyh · · 28731 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

Go 语言标准库 bytes ,实现了对字节数组的各种操作。 It is analogous to the facilities of strings package. (它和string 标准包提供的功能类似)
提供的功能如下;

  • 字节切片 处理函数
    • 基本处理函数
    • 字节切片比较函数
    • 前后缀检查函数
    • 字节切片位置索引函数
    • 分割函数
    • 大小写处理函数
    • 子字节切片处理函数
  • Buffer 对象
  • Reader 对象

字节切片处理函数


基本处理函数 共七个

  1. Contains() 返回是否包含子切片
  2. Count() 子切片非重叠实例的数量
  3. Map() 函数,将byte 转化为Unicode,然后进行替换
  4. Repeat() 将切片复制count此,返回这个新的切片
  5. Replace() 将切片中的一部分 替换为另外的一部分
  6. Runes() 将 S 转化为对应的 UTF-8 编码的字节序列,并且返回对应的Unicode 切片
  7. Join() 函数,将子字节切片连接到一起。

func Contains(b, subslice []byte) bool

func Contains(b, subslice [] byte) bool 检查字节切片 b ,是否包含子字节切片 subslice

package main

import (
    "bytes"
    "fmt"
)

func main() {
    // 这里不能写成 b := []byte{"Golang"},这里是利用类型转换。
    b := []byte("Golang")
    subslice1 := []byte("go")
    subslice2 := []byte("Go")
    fmt.Println(bytes.Contains(b, subslice1))
    fmt.Println(bytes.Contains(b, subslice2))
}

Counts(s, spe[ []byte) int

func Count(s, sep []byte) int 计算子字节切片 sep 在字节切片 s 中出现的非重叠实例的数量。

package main

import (
    "bytes"
    "fmt"
)

func main() {

    s := []byte("banana")
    sep1 := []byte("ban")
    sep2 := []byte("na")
    sep3 := []byte("a")
    fmt.Println(bytes.Count(s, sep1))
    fmt.Println(bytes.Count(s, sep2))
    fmt.Println(bytes.Count(s, sep3))
}

func Map(mapping func(r rune) rune, s []byte) []byte

Map函数:首先将 s 转化为 UTF-8编码的字符序列,然后使用 mapping 将每个Unicode字符映射为对应的字符,最后将结果保存在一个新的字节切片中。

package main

import (
    "bytes"
    "fmt"
)

func main() {

    s := []byte("同学们,上午好")
    m := func(r rune) rune {
        if r == '上' {
            r = '下'
        }
        return r
    }
    fmt.Println(string(s))
    fmt.Println(string(bytes.Map(m, s)))
}

func Repeat(b []byte, count int) []byte

func Replace(s, old, new []byte, n int) []byte

返回字节切片 S 的一个副本, 并且将前n个不重叠的子切片 old 替换为 new,如果n < 0 那么不限制替换的数量

package main

import (
    "bytes"
    "fmt"
)

func main() {
    s := []byte("google")
    old := []byte("o")
    //这里 new 是一个字节切片,不是关键字了
    new := []byte("oo")
    n := 1
    fmt.Println(string(bytes.Replace(s, old, new, n)))
    fmt.Println(string(bytes.Replace(s, old, new, -1)))
}

func Runes(b []byte) []rune

将字节切片 转化为对应的 UTF-8编码的字节序列,并且返回对应的 Unicode 切片。

package main

import (
    "bytes"
    "fmt"
)
//每个 rune 变量占据 4个字节,等价于 int32
//每个 byte 变量占据1个字节,等价于int8
func main() {
    s := []byte("中华人民共和国")
    r := bytes.Runes(s)
    fmt.Println(string(s), len(s))  //字节切片的长度
    fmt.Println(string(r), len(r))   // rune 切片的长度
}

func Join(s [][]byte, sep []byte) []byte

用字节切片 sep 吧 s中的每个字节切片连接成一个,并且返回.

package main

import (
    "bytes"
    "fmt"
)

func main() {
    // 字节切片 的每个元素,依旧是字节切片。
    s := [][]byte{
        []byte("你好"),
        []byte("世界"),  //这里的逗号,必不可少
    }
    sep := []byte(",")
    fmt.Println(string(bytes.Join(s, sep)))

    var a = []int{1,
        2,
        3,
        5,  //这里的逗号,也必不可少
    }
    fmt.Println(a)

    var b = []int{1, 2, 3, 4, 5}  //这里最后一个元素不需要逗号
    fmt.Println(b)
}

字节切片比较函数

func Compare(a, b[]byte) int : 返回整数:1, 0 ,-1
func Equal(a, b []byte) bool: 返回true or false
func EqualFold(a, b []byte) bool : 忽略大小写:返回 true or false

package main

import (
    "bytes"
    "fmt"
)

func main() {
    a := []byte("abc")
    b := []byte("ABC")
    s := []byte("GOLANG")
    t := []byte("golang")

    fmt.Println(bytes.Compare(a, b))
    fmt.Println(bytes.Equal(a, b))
    fmt.Println(bytes.EqualFold(s, t))
}
输出为:
1
false
true

字节切片 前后缀 检查函数

func HasPreifx(s, prefix []byte) bool
func HasSuffix(s, suffix []byte) bool

字节切片 位置索引函数

  • func Index(s, sep []byte) int 返回字节切片在s中第一次出现的位置(索引从0 开始),不存在返回-1.
  • func IndexAny(s []byte, chars string) 将字节切片解释为 UTF-8的字符,返回 chars 中任何一个字符在s中 第一次出现的位置。(chars 中保存的是 Unicode字符集)
  • func IndexByte(s []byte, c byte) int
  • func IndexFunc(s []byte, f func(r rune)bool) int 将 s 解释成 UTF-8字节序列, 并且返回第一个使得 f(c) = ture的字符 c的索引位置。
  • func IndexRue(s []byte, r rune)
  • func LastIndex(s ,sep []byte) int
  • func LastIndexAny (s []byte, chars string) int
  • func LastIndexFunc(s []byte, f func(r rune) bool) int

字节切片 分割函数

  • func Fields(s []byte) [][]byte 将字节切片 s 按照 一个或者连续多个空白字符 分割成 多个字节切片。如果 s 只包含空白字符,则返回 空字节切片。
package main

import (
    "bytes"
    "fmt"
)

func main() {
    s := []byte(" I'm a student. ")
    for _, f := range bytes.Fields(s) {
        fmt.Printf("%q ", f)
    }

    s1 := []byte("   ")
    s2 := bytes.Fields(s1)

    fmt.Println(len(s2), s2 == nil)
}
程序输出如下:
"I'm" "a" "student." 0 false
  • func FieldsFunc(s []byte, f func(r rune) bool) [][]byte, 首先将s 解释成 Unicode 字符序列,然后用函数 f 进行测试。
  • func Split(s, sep []byte) [][]byte 按照字节序列 sep 进行分割
  • func SplitN(s, sep []byte, n int) [][]byte 按照字节序列 sep 进行分割,并且 可以设置 分割成的字节切片的个数,n == -1表示返回所有的子切片。
  • func SplitAfter(s, sep[] byte) [][]byte,这里是不舍弃 sep,而是保留sep。
  • func SplitAfterN(s, sep[] byte, int n) [][]byte 和上次是一样的。

    字节切片大小写处理函数

    • func Title(s []byte) []byte 返回s的一个副本,并且将S中每个单词的首字母转化成 Unicode大写字符。
    • func ToTitle(s []byte) []byte 将其中的所有Unicode字符转化成大写。
    • func ToTitleSpecial(_case unicode.SpecialCase, s []byte) []byte
    • func ToLower(s []byte) []byte
    • func ToLowerSpeical(_case unicode.SpecialCase, s[]byte) []byte
    • func ToUpper(s []byte) []byte
    • func ToUpperSpecial (_case unicode.SpecialCase, s []byte) []byte

子字节 切片 处理函数

将 一个 字节切片截端,然后返回新的字节切片

func Trim(s []byte, cutset string) []byte
func TrimFunc(s []byte, f func(r rune) bool) []byte
func TrimLeft(s []byte, cutset string) []byte
func TrimLeftFunc(s []byte, f func(r rune) bool) []byte
func TrimRight(s []byte, cutset string) []byte
func TrimRightFunc (s []byte, f func(r rune) bool) []byte
func TrimPrefix(s, prefix []byte) []byte
func TrimSuffix(s, suffix []byte) []byte
func TrimSpace(s []byte) []byte

Buffer and Reader

现在需要对字节切片进行读写: 比如说,不停地向字节切片中 写入字符串, 从字节切片中读取字符串等等操作。
于是我们有了 Buffer and Reader.


bytes.Buffer

Buffer 是 bytes 包中的一个 type Buffer struct{…}

A buffer is a variable-sized buffer of bytes with Read and Write methods. The zero value for Buffer is an empty buffer ready to use. (是一个变长的 buffer,具有 Read 和Write 方法。 Buffer 的 零值 是一个 空的 buffer,但是可以使用)
在我看来: Buffer 是一种抽象,想想成一个不限容量蓄水池,你可以向其中加水,同时也可以向其中取出水。(存入数据,和取数据)

  1. 创建 一个 Buffer (其实底层就是一个 []byte, 字节切片)
  2. 向其中写入数据 (Write mtheods)
  3. 从其中读取数据 (Write methods)

创建 Buffer

var b bytes.Buffer  //直接定义一个 Buffer 变量,而不用初始化
b.Writer([]byte("Hello ")) // 可以直接使用

b1 := new(bytes.Buffer)   //直接使用 new 初始化,可以直接使用
// 其它两种定义方式
func NewBuffer(buf []byte) *Buffer
func NewBufferString(s string) *Buffer

Buffer 基本函数

func (b *Buffer) Bytes() []byte 返回 没有读取的 内容
func (b *Buffer) Grow() (n int) 增加 buffer 的容量
func (b *Buffer) Len() int 返回没有读取的内容的长度
func (b *Buffer) Next(n int) []byte 返回没有读取的 n个字节,副作用,就像采用了Read 方法进行了读一样。

向 Buffer 中读取数据

func (*Buffer) Read(p []byte) (n int, err error) 从 Buffer 从读取 len(p) 的数据,直到 Buffer 没有数据可以读取。 返回值是读取数据的字节数。 如果没有数据可以读取,那么err 的值是 io.EOF
func (*Buffer) ReadByte() (c byte, err error)
func (*Buffer) ReadBytes(delim byte) (line []byte, err error) 遇到第一个 delim 的时候,将数据返回。
func (*Buffer)ReadRune() (r rune, err error)
func (*Buffer) ReadString(delim byte) (line string, err error)
func (*Buffer) Reset() 将数据清空,没有数据可读
func (*Buffer) String() string 将未读取的数据返回成 string

func (*Buffer) Truncate(n int) 在Buffer中保留 n个未读的数据。

func (*Buffer) UnreadByte() error
func (*Buffer) UnreadRune() error 小心返回错误。

func (*Buffer) ReadFrom( r o.Reader) (n int64, err error) 从 IO 接口 对象 r中读取数据,并且写入到 buffer中,知道 r.Read 返回 io.EOF。 (当然)

向 Buffer 中写入数据

func (b * Buffer) Write(p []byte) (n int, err error)把字节切片 p 写入到buffer中去。
func (b *Buffer) WriteByte(c byte) error
func (b *Buffer) WriteRune(c byte) error
func (b *Buffer) WriteString(s string) (n int, err error)
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) 将Buffer 中的数据写入到 I/O对象 writer 中去,知道数据为空,或者遇到错误。


bytes.Reader

Reader 是另外一个可以对切片进行操作的方法,但是 Reader只可以对数据进行 读取操作,不从向切片中写入数据。Reader 支持对切片进行Seek() 定位 操作。


总结

说明了一下几点:
1. []byte 字节切片是 golang中的(最)重要的工具,好好利用字节切片
2. 掌握好对字节切片进行操作的工具。 (有好的工具很重要)
3. 多多写程序,才可以有收获


有疑问加站长微信联系(非本文作者)

本文来自:CSDN博客

感谢作者:xiaorenwuzyh

查看原文:Golang -- 字节切片

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

28731 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传