Skip to content

Instantly share code, notes, and snippets.

@ieee0824
Last active November 17, 2017 05:26
Show Gist options
  • Save ieee0824/168a592825ccb4920a8d7fcf757789e5 to your computer and use it in GitHub Desktop.
Save ieee0824/168a592825ccb4920a8d7fcf757789e5 to your computer and use it in GitHub Desktop.
func Fields(s string) []stringを読み解く

strings packageのFields(s string)[]string関数の実装が興味深い

https://golang.org/src/strings/strings.go?s=7967:7997#L310

310行目について

var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1}

ascii codeは8bitあれば表現することができる。
つまり長さが256のuint8のフラグを使えば表現できる。
全てのascii文字のうちスペースとして定義される文字について予めフラグを立てている処理である。

322行目について

322を読む前に以下の実装だとどういう出力が得られるだろうか

var str = "ほげ"
fmt.Println(len(str))

答えは6である
go言語においてstring型のlenを取った時の長さの見え方は[]byte型にcastした時のものが見える
つまり次のように考えるとわかりやすい

var str = "ほげ"
fmt.Println(len([]byte(str)))

UTF-8において平仮名一文字は今のところ3オクテットで表現されるので2文字あると6オクテットになりlenを取った時6が帰ってくる

つまり322~328行目のforループはとある文字列を[]byteとみなしてsliceの0番目から順番に処理していくことになる
ちなみに次のようにも書けそうであるが意味が変わるので注意

for i, r := range s {
    setBits |= r
    isSpace := int(asciiSpace[r])
    n += wasSpace & ^isSpace
    wasSpace = isSpace
}

rangeを使った場合rはruneになる

324行目について

ascii文字列は8bitとして表現した時必ず0x7f未満に収まる
2進数に直すと0b01111111になるわけだが、もし文字列が全てascii codeで構成された場合全ての文字をor演算した場合必ず最上位bitは0であるということになる
それに対してutf-8の文字列においては必ずorを取った時に最上位bitが経つのでutf-8文字列かascii文字のみの文字列を判定できる

結果的に322~328行目が何をやっているかと言うとfieldの要素数とutf-8かasciiかの判定のための情報を作っている
https://play.golang.org/p/egc-EI4Vvr

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment