Go源码学习:bytes包 - 1.2 - bytes.go -(2)

bytes包官方文档

Go源码学习-索引目录

上一篇:
Go源码学习:bytes包 - 1.2 - bytes.go -(1)

11、LastIndex:查找字节切片中子切片的最后一个实例索引

// LastIndex 返回字节切片 s 中子切片 sep 的最后一个实例的索引,如果 sep 不在 s 中则返回 -1。
func LastIndex(s, sep []byte) int {
    n := len(sep)
    switch {
    case n == 0:
        return len(s)
    case n == 1:
        return bytealg.LastIndexByte(s, sep[0])
    case n == len(s):
        if Equal(s, sep) {
            return 0
        }
        return -1
    case n > len(s):
        return -1
    }
    return bytealg.LastIndexRabinKarp(s, sep)
}

解释:

  • LastIndex 是一个函数,用于查找字节切片 s 中子切片 sep 的最后一个实例的索引。
  • 函数内部根据不同情况选择不同的查找方式,包括空子切片、单字节子切片、全匹配子切片等。
  • 调用了 bytealg 包中的具体实现函数来执行最后索引的查找操作。

作用:

  • LastIndex 函数的作用是在字节切片中查找指定子切片的最后一个实例,并返回其索引。如果子切片不在字节切片中,则返回 -1。

12、LastIndexByte:查找字节在字节切片中的最后一个实例索引

// LastIndexByte 返回字节切片 s 中字节 c 的最后一个实例的索引,如果 c 不在 s 中则返回 -1。
func LastIndexByte(s []byte, c byte) int {
    return bytealg.LastIndexByte(s, c)
}

解释:

  • LastIndexByte 是一个函数,用于查找字节切片 s 中字节 c 的最后一个实例的索引。
  • 函数内部调用了 bytealg 包中的 LastIndexByte 函数来执行具体的字节查找操作。

作用:

  • LastIndexByte 函数的作用是在字节切片中查找指定字节的最后一个实例,并返回其索引。如果指定字节不在字节切片中,则返回 -1。

13、IndexRune:查找字节切片中指定 rune 的首次出现索引

// IndexRune 将字节切片 s 解释为 UTF-8 编码的码点序列。
// 它返回给定 rune 在 s 中首次出现的字节索引。
// 如果 rune 不在 s 中,则返回 -1。
// 如果 r 是 utf8.RuneError,则返回任何无效 UTF-8 字节序列的第一个实例。
func IndexRune(s []byte, r rune) int {
    switch {
    case 0 <= r && r < utf8.RuneSelf:
        return IndexByte(s, byte(r))
    case r == utf8.RuneError:
        for i := 0; i < len(s); {
            r1, n := utf8.DecodeRune(s[i:])
            if r1 == utf8.RuneError {
                return i
            }
            i += n
        }
        return -1
    case !utf8.ValidRune(r):
        return -1
    default:
        var b [utf8.UTFMax]byte
        n := utf8.EncodeRune(b[:], r)
        return Index(s, b[:n])
    }
}

解释:

  • IndexRune 是一个函数,用于将字节切片 s 解释为 UTF-8 编码的码点序列,并查找给定 runes 中首次出现的字节索引。
  • 函数内部根据不同情况选择不同的查找方式,包括单字节 rune、无效 UTF-8 字节序列、有效 rune 等。
  • 调用了 IndexByteutf8.DecodeRuneutf8.ValidRuneutf8.EncodeRune 等函数来执行具体的查找和编解码操作。

作用:

  • IndexRune 函数的作用是在字节切片中查找指定 rune 的首次出现索引。
  • 可以处理单字节 rune、无效 UTF-8 字节序列等情况,提供灵活的查找功能。

14、IndexAny:查找字节切片中任一字符的首次出现索引

// IndexAny 将字节切片 s 解释为 UTF-8 编码的 Unicode 码点序列。
// 它返回在 s 中任一 Unicode 码点在 chars 中首次出现的字节索引。
// 如果 chars 为空或没有共同的码点,则返回 -1。
func IndexAny(s []byte, chars string) int {
    if chars == "" {
        // 避免扫描整个 s。
        return -1
    }
    if len(s) == 1 {
        r := rune(s[0])
        if r >= utf8.RuneSelf {
            // 搜索 utf8.RuneError。
            for _, r = range chars {
                if r == utf8.RuneError {
                    return 0
                }
            }
            return -1
        }
        if bytealg.IndexByteString(chars, s[0]) >= 0 {
            return 0
        }
        return -1
    }
    if len(chars) == 1 {
        r := rune(chars[0])
        if r >= utf8.RuneSelf {
            r = utf8.RuneError
        }
        return IndexRune(s, r)
    }
    if len(s) > 8 {
        if as, isASCII := makeASCIISet(chars); isASCII {
            for i, c := range s {
                if as.contains(c) {
                    return i
                }
            }
            return -1
        }
    }
    var width int
    for i := 0; i < len(s); i += width {
        r := rune(s[i])
        if r < utf8.RuneSelf {
            if bytealg.IndexByteString(chars, s[i]) >= 0 {
                return i
            }
            width = 1
            continue
        }
        r, width = utf8.DecodeRune(s[i:])
        if r != utf8.RuneError {
            // r 是 2 到 4 字节
            if len(chars) == width {
                if chars == string(r) {
                    return i
                }
                continue
            }
            // 如果可用,使用 bytealg.IndexString 提高性能。
            if bytealg.MaxLen >= width {
                if bytealg.IndexString(chars, string(r)) >= 0 {
                    return i
                }
                continue
            }
        }
        for _, ch := range chars {
            if r == ch {
                return i
            }
        }
    }
    return -1
}

解释:

  • IndexAny 是一个函数,用于将字节切片 s 解释为 UTF-8 编码的 Unicode 码点序列,并查找在 s 中任一 Unicode 码点在 chars 中首次出现的字节索引。
  • 函数内部根据不同情况选择不同的查找方式,包括单字符、单字节 rune、ASCII 字符集等。
  • 调用了 IndexRunebytealg.IndexByteStringutf8.DecodeRunebytealg.IndexString 等函数来执行具体的查找和编解码操作。

作用:

  • IndexAny 函数的作用是在字节切片中查找任一字符在指定字符集 chars 中首次出现的索引。
  • 可以处理单字符、单字节 rune、多字节 rune、ASCII 字符集等情况,提供灵活的查找功能。

15、LastIndexAny:获取最后一个匹配字符的字节索引

这部分代码定义了 LastIndexAny 函数,用于在字节切片 s 中查找字符串 chars 中任一 Unicode 字符的最后一个匹配,并返回该字符的字节索引。如果 chars 为空或在 s 中没有共同的字符,则返回 -1。

// LastIndexAny 将 s 解释为一系列 UTF-8 编码的 Unicode 代码点。
// 它返回 s 中 chars 中任一 Unicode 代码点的最后一次出现的字节索引。
// 如果 chars 为空或在 s 中没有共同的字符,则返回 -1。
func LastIndexAny(s []byte, chars string) int {
    // 如果 chars 为空,则避免扫描整个 s。
    if chars == "" {
        return -1
    }

    // 如果 s 的长度大于 8,且 chars 是 ASCII 字符集,优化处理。
    if len(s) > 8 {
        if as, isASCII := makeASCIISet(chars); isASCII {
            // 从 s 的末尾开始遍历,查找匹配字符的索引。
            for i := len(s) - 1; i >= 0; i-- {
                if as.contains(s[i]) {
                    return i
                }
            }
            return -1
        }
    }

    // 如果 s 的长度为 1,处理单字节情况。
    if len(s) == 1 {
        r := rune(s[0])
        if r >= utf8.RuneSelf {
            // 对于多字节字符,检查是否与 chars 中的任一字符匹配。
            for _, r = range chars {
                if r == utf8.RuneError {
                    return 0
                }
            }
            return -1
        }
        // 对于单字节字符,使用 bytealg.IndexByteString 查找匹配字符。
        if bytealg.IndexByteString(chars, s[0]) >= 0 {
            return 0
        }
        return -1
    }

    // 如果 chars 的长度为 1,处理单字符情况。
    if len(chars) == 1 {
        cr := rune(chars[0])
        if cr >= utf8.RuneSelf {
            cr = utf8.RuneError
        }
        // 从 s 的末尾开始解码最后一个 Unicode 字符,并查找匹配字符的索引。
        for i := len(s); i > 0; {
            r, size := utf8.DecodeLastRune(s[:i])
            i -= size
            if r == cr {
                return i
            }
        }
        return -1
    }

    // 通用情况:从 s 的末尾开始遍历,查找最后一个匹配字符的索引。
    for i := len(s); i > 0; {
        r := rune(s[i-1])
        if r < utf8.RuneSelf {
            // 对于单字节字符,使用 bytealg.IndexByteString 查找匹配字符。
            if bytealg.IndexByteString(chars, s[i-1]) >= 0 {
                return i - 1
            }
            i--
            continue
        }
        // 对于多字节字符,解码最后一个 Unicode 字符,并查找匹配字符的索引。
        r, size := utf8.DecodeLastRune(s[:i])
        i -= size
        if r != utf8.RuneError {
            // r 是 2 到 4 字节
            if len(chars) == size {
                if chars == string(r) {
                    return i
                }
                continue
            }
            // 使用 bytealg.IndexString 进行性能优化(如果可用)。
            if bytealg.MaxLen >= size {
                if bytealg.IndexString(chars, string(r)) >= 0 {
                    return i
                }
                continue
            }
        }
        // 遍历 chars,查找匹配字符的索引。
        for _, ch := range chars {
            if r == ch {
                return i
            }
        }
    }
    return -1
}

解释:

  • LastIndexAny 函数用于在字节切片中查找字符串中任一 Unicode 字符的最后一个匹配,并返回该字符的字节索引。
  • 函数先处理一些特殊情况,如空字符集或单字符集。
  • 对于较长的字节切片,且字符集为 ASCII 字符集时,进行优化处理。
  • 在循环中从字节切片的末尾开始遍历,解码 Unicode 字符,并查找匹配字符的索引。
  • 使用不同的算法处理单字节字符和多字节字符,以及性能优化的考虑。

作用:

  • LastIndexAny 主要用于在字节切片中查找最后一个匹配字符的位置。
  • 通过考虑单字节字符和多字节字符的不同情况,以及对较长字节切片和 ASCII 字符集的优化,提高了查找效率。

16、genSplit:通用切割方法

这部分代码定义了 genSplit 方法,用于根据指定的分隔符切割字节切片,并返回切割后的子切片数组。

// genSplit:通用切割方法,根据 sep 分隔字节切片 s,返回切割后的子切片数组。
// sepSave 参数表示是否在子切片中保留 sepSave 字节的分隔符。
// n 参数确定要返回的子切片数量:
//   n > 0:最多返回 n 个子切片;最后一个子切片将是未切割的剩余部分。
//   n == 0:结果为 nil(零个子切片)。
//   n < 0:返回所有子切片。
func genSplit(s, sep []byte, sepSave, n int) [][]byte {
    // 如果 n 为零,返回 nil。
    if n == 0 {
        return nil
    }
    // 如果分隔符为空,调用 explode 方法进行切割。
    if len(sep) == 0 {
        return explode(s, n)
    }
    // 如果 n 为负数,设定为 s 中 sep 的数量加一。
    if n < 0 {
        n = Count(s, sep) + 1
    }
    // 如果 n 大于 s 的长度加一,设定为 s 的长度加一。
    if n > len(s)+1 {
        n = len(s) + 1
    }

    // 初始化子切片数组 a,长度为 n。
    a := make([][]byte, n)
    n--
    i := 0
    // 循环切割过程,直到达到指定的子切片数量。
    for i < n {
        // 在 s 中找到分隔符 sep 的位置 m。
        m := Index(s, sep)
        // 如果找不到分隔符,跳出循环。
        if m < 0 {
            break
        }
        // 将 s 的起始位置到 m+sepSave 的部分切割,并存储到子切片数组 a 中。
        a[i] = s[:m+sepSave : m+sepSave]
        // 更新 s 的起始位置,去除已切割的部分和分隔符。
        s = s[m+len(sep):]
        i++
    }
    // 将剩余部分存储到最后一个子切片。
    a[i] = s
    return a[:i+1]
}

解释:

  • genSplit 方法是一个通用的切割方法,用于根据指定的分隔符切割字节切片。
  • 方法的参数包括要切割的字节切片 s、分隔符 sep、是否在子切片中保留分隔符的字节数 sepSave 以及要返回的子切片数量 n
  • 首先,处理特殊情况:如果 n 为零,返回 nil;如果分隔符为空,调用 explode 方法进行切割;如果 n 为负数,设定为 s 中分隔符的数量加一;如果 n 大于 s 的长度加一,设定为 s 的长度加一。
  • 初始化子切片数组 a,长度为 n
  • 通过循环进行切割过程,直到达到指定的子切片数量。
  • 在循环中,在 s 中找到分隔符 sep 的位置,并将切割的部分存储到子切片数组 a 中。
  • 更新 s 的起始位置,去除已切割的部分和分隔符。
  • 将剩余部分存储到最后一个子切片。
  • 返回切割后的子切片数组。

作用:

  • genSplit 方法的主要作用是根据指定的分隔符将字节切片切割成多个子切片,并返回这些子切片组成的数组。
  • 可以控制返回的子切片数量,并选择是否在子切片中保留分隔符的部分字节。

17、SplitN:切割成指定数量的子切片

这部分代码定义了 SplitN 方法,用于将字节切片 s 切割成由分隔符 sep 分隔的子切片数组,并返回这些子切片。

// SplitN:将字节切片 s 切割成由分隔符 sep 分隔的子切片数组,并返回这些子切片。
// 如果 sep 为空,则在每个 UTF-8 序列后进行切割。
// count 参数确定要返回的子切片数量:
//
//  n > 0:最多返回 n 个子切片;最后一个子切片将是未切割的剩余部分。
//  n == 0:结果为 nil(零个子切片)。
//  n < 0:返回所有子切片。
//
// 要围绕第一个分隔符进行切割,请参见 Cut 方法。
func SplitN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) }

解释:

  • SplitN 方法是用于切割字节切片的函数,返回由分隔符 sep 分隔的子切片数组。
  • 如果分隔符为空,则在每个 UTF-8 序列后进行切割。
  • 参数 n 确定要返回的子切片数量:
    • 如果 n 大于 0,最多返回 n 个子切片,最后一个子切片将是未切割的剩余部分。
    • 如果 n 等于 0,结果为 nil(零个子切片)。
    • 如果 n 小于 0,返回所有子切片。

18、SplitAfterN:切割成指定数量的子切片(保留分隔符)

这部分代码定义了 SplitAfterN 方法,用于将字节切片 s 切割成由分隔符 sep 分隔的子切片数组,并返回这些子切片。与 SplitN 不同的是,SplitAfterN 会在每个分隔符后保留分隔符的部分字节。

// SplitAfterN:将字节切片 s 切割成由分隔符 sep 分隔的子切片数组,并返回这些子切片。
// 与 SplitN 不同,SplitAfterN 会在每个分隔符后保留分隔符的部分字节。
// count 参数确定要返回的子切片数量:
//
//  n > 0:最多返回 n 个子切片;最后一个子切片将是未切割的剩余部分。
//  n == 0:结果为 nil(零个子切片)。
//  n < 0:返回所有子切片。
func SplitAfterN(s, sep []byte, n int) [][]byte {
    return genSplit(s, sep, len(sep), n)
}

解释:

  • SplitAfterN 方法是用于切割字节切片的函数,返回由分隔符 sep 分隔的子切片数组。
  • SplitN 不同,SplitAfterN 会在每个分隔符后保留分隔符的部分字节。
  • 参数 n 确定要返回的子切片数量:
    • 如果 n 大于 0,最多返回 n 个子切片,最后一个子切片将是未切割的剩余部分。
    • 如果 n 等于 0,结果为 nil(零个子切片)。
    • 如果 n 小于 0,返回所有子切片。

19、Split:切割成所有子切片

这部分代码定义了 Split 方法,用于将字节切片 s 切割成由分隔符 sep 分隔的子切片数组,并返回这些子切片。相当于调用 genSplit 方法,将 count 参数设定为 -1。

// Split:将字节切片 s 切割成由分隔符 sep 分隔的子切片数组,并返回这些子切片。
// 如果 sep 为空,则在每个 UTF-8 序列后进行切割。
// 等效于使用 count 参数为 -1 的 SplitN 方法。
//
// 要围绕第一个分隔符进行切割,请参见 Cut 方法。
func Split(s, sep []byte) [][]byte { return genSplit(s, sep, 0, -1) }

解释:

  • Split 方法是用于切割字节切片的函数,返回由分隔符 sep 分隔的子切片数组。
  • 如果分隔符为空,则在每个 UTF-8 序列后进行切割。
  • 等效于使用 genSplit 方法,将 count 参数设定为 -1。

20、SplitAfter:切割成所有子切片(保留分隔符)

这部分代码定义了 SplitAfter 方法,用于将字节切片 s 切割成由分隔符 sep 分隔的子切片数组,并返回这些子切片。与 Split 不同的是,SplitAfter 会在每个分隔符后保留分隔符的部分字节。

// SplitAfter:将字节切片 s 切割成由分隔符 sep 分隔的子切片数组,并返回这些子切片。
// 与 Split 不同,SplitAfter 会在每个分隔符后保留分隔符的部分字节。
// 等效于使用 count 参数为 -1 的 SplitAfterN 方法。
func SplitAfter(s, sep []byte) [][]byte {
    return genSplit(s, sep, len(sep), -1)
}

解释:

  • SplitAfter 方法是用于切割字节切片的函数,返回由分隔符 sep 分隔的子切片数组。
  • Split 不同,SplitAfter 会在每个分隔符后保留分隔符的部分字节。
  • 等效于使用 genSplit 方法,将 count 参数设定为 -1。

作用:

  • SplitAfter 方法的作用与 Split 方法类似,不同之处在于保留分隔符的部分字节。
  • 12
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风不归Alkaid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值