目次
目次
bytes パッケージについて
bytes package はバイトスライスを操作するための関数を提供します。
$ gocloc --not-match=test bytes
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
Go 3 149 459 1405
-------------------------------------------------------------------------------
TOTAL 3 149 459 1405
-------------------------------------------------------------------------------
It is analogous to the facilities of the strings package.
(go doc)
bytes/strings
は類似しており、かつ多くの便利メソッドが提供されています。
メソッド内の実装について触れつつ、どのような便利メソッドが提供されているか見ていきます。
前提知識として、Go における文字列、バイト、ルーンの取り扱いについてはこちらの記事がとてもわかりやすいです。
Strings, bytes, runes and characters in Go - The Go Programming Language
また、Go では文字列・バイト・ルーンを相互に変換可能です。
The Go Programming Language Specification - The Go Programming Language
Clone
Go 1.20 から追加されました。引数に渡されたバイトスライスのコピーを返します。
もとのバイトスライスへ影響を与えず操作したい場合に利用する便利メソッドです。
Compare
2 つのバイトスライスの並び替えの順番を決める場合などに利用できます。
2 つのバイトスライスを比較し、a==b
場合は 0、a<b
の場合は-1、a>b
の場合は 1 を返します。
アセンブリで実装されたinternal/bytealgのメソッドが呼ばれます。
Contains
内部ではIndex
系の関数が呼ばれる便利メソッドです。
特定のバイトスライスが存在するか検証します。何らかの入力に対するバリデーション等に利用できます。
Contains
func Contains(b, subslice []byte) bool
Index 関数のラッパーです。
ContainsAny
func ContainsAny(b []byte, chars string) bool
IndexAny 関数のラッパーです。
ContainsRune
func ContainsRune(b []byte, r rune) bool
IndexRune 関数のラッパーです。
Index
検索対象に検索バイトが含まれる場合は、最初の Index を返し、存在しない場合は-1 を返します。
具体的な処理はこのようになります。
検索バイトの長さが 0 の場合 0 を返します。
検索の長さが 1 の場合、アセンブリで実装された IndexByte が呼ばれます。
検索の長さが同じ場合は、Equal 関数を呼び一致するか検証します
検索対象の長さが 32 以下かつ検索バイトスライスの長さがともに 16 以下の場合はアセンブリで実装された `bytelag.Index` 関数を利用します
検索対象の長さが 32 以下かつ検索バイトスライスの長さが 16 より大きい場合は、先頭が一致した箇所があるまで検証し、`bytealg.Index` より高速な`bytealg.IndexByte` 関数を用います。
関数内では`fails`を保持しており、`bytealg.IndexByte` でご検知が多い場合は、`bytealg.Index`を使用します
IndexAny
func IndexAny(s []byte, chars string) int
bytes に chars の文字列のいずれかの文字が含まれるか調べます。存在しない場合は-1 を返し、存在する場合は最初の index を返します。
具体的な処理はこのようになります。
無効な文字は`\uFFFD`に置き換えられるため、この文字が含まれていないか調べます。含まれている場合は 0 を返します。
バイトの長さが 8 より小さい場合は、すべて ASCII に変換しつつ、変換出来ないものがないか検証し、Bytes に一致するものがないか調べます。
それ以外の場合は、`bytealg.IndexByteString` や`bytealg.IndexString`を利用しつつ愚直に調べていきます。
何故、文字数が少ない場合はアセンブリのコードを呼ばないのか分からなかったのですが、オーバーヘッドなのかなと思いました。こちらについては、後ほど計測しつつ調べていきたいです。
IndexByte
func IndexByte(b []byte, c byte) int
bytealg.IndexByte
が呼ばれます。
IndexRune
func IndexRune(s []byte, r rune) int
具体的な処理はこのようになります。
`RuneSelf`(シングルバイト)の場合は`betealg.IndexByte`を利用します
`utf8.RuneError`場合は、文字列から無効なルーンを一つずつ調べ最初に一致するものを返します
無効なルーンの場合は-1 を返します
それ以外の場合は `rune` を `byte` に変換し Index 関数を呼びます
Count
s 内の sep に重複しない数を数えます。sep のスライスが空の場合、1+s の UTF-8 エンコードされた数を返します。
Cut
func Cut(s, sep []byte) (before, after []byte, found bool)
Sep の前後をスライスで返します。
Strings の例ですが、Index 関数で探してスライス二分割する処理を単純にできます 。
Go 1.18: Cut added to strings/bytes - DEV Community 👩💻👨💻
- func CutPrefix(s, prefix []byte) (after []byte, found bool)
- func CutSuffix(s, suffix []byte) (before []byte, found bool)
Equal
Equal
a,b が同じ長さで同じバイトであるかを返します。
EqualFold
func EqualFold(s, t []byte) bool
大文字と小文字を区別せずに同じバイトのスライスであるかを返します。
func Fields(s []byte) [][]byte
スペース で分割します。
Prefix
func HasPrefix(s, prefix []byte) bool
バイトスライスが s で始まるか調べる便利メソッドです。
Join
Join
func Join(s [][]byte, sep []byte) []byte
新しいバイトスライスを作成し、複数のバイトスライス s を連結します。sep は s の要素の間に挿入されます。
Index
LastIndex
func LastIndex(s, sep []byte) int
一致する最後のインスタンスのインデックスを返します。
- func LastIndexAny(s []byte, chars string) int
- func LastIndexByte(s []byte, c byte) int
- func LastIndexFunc(s []byte, f func(r rune) bool) int
- func Map(mapping func(r rune) rune, s []byte) []byte
Repeat/Replace/Split
Repeat
func Repeat(b []byte, count int) []byte
バイトスライス b を count 回繰り返したバイトスライスを返します。
オーバーフローする場合は Panic が発生します。
パフォーマンスのため、チャンクを作り繰り返しのデータをスライスに追加していきます。パフォーマンスの劣化を防ぐため、 チャンクのサイズは最大 8kb になります。
Replace
func Replace(s, old, new []byte, n int) []byte
s にある n 回目の old を new に置き換えます。
ReplaceAll
func ReplaceAll(s, old, new []byte) []byte
s にある old を new に置き換えます。
Runes
utf8.DecodeRune
を利用し、バイトスライスと等価な rune を返します。
Split
func Split(s, sep []byte) [][]byte
s を sep で区切りバイトスライスのスライスを返します。
- func SplitAfter(s, sep []byte) [][]byte
- func SplitAfterN(s, sep []byte, n int) [][]byte
- func SplitN(s, sep []byte, n int) [][]byte
Lower/Upper
ToLower
すべての Unicode を小文字にしたバイトスライスのコピーを返します。
具体的な処理はこのようになります。
ASCII かつ大文字が存在しない場合はバイトスライスにコピーしそのまま返します。
ASCII のみかつシングルバイトの場合は’a’-‘A’分ずらします。
それ以外の場合は`unicode.ToLower`を利用します。
シングルバイトで場合分けをすることで効率的に処理をしています。
- func ToLowerSpecial(c unicode.SpecialCase, s []byte) []byte
- func ToTitle(s []byte) []byte
- func ToTitleSpecial(c unicode.SpecialCase, s []byte) []byte
- func ToUpper(s []byte) []byte
- func ToUpperSpecial(c unicode.SpecialCase, s []byte) []byte
- func ToValidUTF8(s, replacement []byte) []byte
Trim
Trim
func Trim(s []byte, cutset string) []byte
s の先頭及び末尾から cutset に含まれる byte をすべて取り除きます。
func main() {
fmt.Printf("[%q]", bytes.Trim([]byte(" !!! Achtung! Achtung! !!! "), "! "))
}
// ["Achtung! Achtung"]
- 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 TrimPrefix(s, prefix []byte) []byte
- func TrimRight(s []byte, cutset string) []byte
- func TrimRightFunc(s []byte, f func(r rune) bool) []byte
- func TrimSpace(s []byte) []byte
- func TrimSuffix(s, suffix []byte) []byte
Buffer
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 メソッドを持つ可変サイズのシンプルなバイトバッファです。