いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Goメモ-37 (stringとruneとbyteの変換)

概要

よく忘れるので、自分用にメモです。

Goの文字列は、 string 型で表現されます。 stringは、文字列をバイト列で持っています。 なので、string に対して、len()するとバイト数が取得できます。

Goの文字は rune 型で表現されます。 runeは、文字をUnicodeコードポイントで持っています。 なので、[]runeに対して len() すると文字数が取得できます。

string[]rune[]byteは相互に変換可能です。

  • []bytestring を与える事によって、その文字列のバイト列になる
  • string[]byte を与える事によって、バイト列の文字列となる
  • []runestring を与える事によって、その文字列のrune列となる
  • string[]rune を与える事によって、そのrune列の文字列となる

上を見ると、stringが中継地点となっていて runebyte を変換する場合は

一旦 string にしてから、望む方向へ変換してやればいいことがわかります。

補足として、途中のstring変換をせずに直接 rune と byte を変換するには utf8.EncodeRune() などを利用すればできます。

こういうのは、実際のコード見たほうが早いと思いますので、以下にサンプルです。

サンプル

package string_

import (
    "fmt"
    "unicode/utf8"
)

// StringRuneByteConvert は、文字列とルーンとバイト列の変換のサンプルです.
func StringRuneByteConvert() error {
    // -----------------------------------------------------
    // Goでの文字列は string 型で表現される。
    // string は、文字列をバイト列で表現しているもの。
    // なので、string に対して len() とするとバイト数が取得できる
    // (Goの文字列表現はUTF-8)
    //
    // Goでの文字は rune 型で表現される。
    // rune は、文字をUnicodeコードポイントで表現しているもの。
    // なので、 []rune に対して len() とすると文字数が取得できる。
    //
    // string/[]rune/[]byte は相互に変換可能。
    //
    // []byte に string を与える事によって、その文字列のバイト列になる
    // string に []byte を与える事によって、バイト列の文字列となる
    // []rune に string を与える事によって、その文字列のrune列となる
    // string に []rune を与える事によって、そのrune列の文字列となる
    //
    // 上を見る通り、stirng が中継地点となっていて
    // rune と byte を変換する場合は、一旦 string にしてから
    // 望む方向へ変換する。
    //
    // utf8.EncodeRune() を利用することで中間生成のstringを省く事もできる.
    //
    // REFERENCES::
    //   - https://stackoverflow.com/questions/29255746/how-encode-rune-into-byte-using-utf8-in-golang
    //   - https://qiita.com/masakielastic/items/01a4fb691c572dd71a19
    //   - https://golang.org/ref/spec#Conversions_to_and_from_a_string_type
    // -----------------------------------------------------
    s := "こんにちわworld"

    // そのまま len(s) とすると、バイト数となる
    fmt.Printf("len(s) == %d\n", len(s))

    // runeに変換
    r := []rune(s)
    fmt.Printf("len(r) == %d\n", len(r))

    // runeはUnicodeコードポイントを示しているので日本語などでは
    // 一つのruneがNバイトとなる.
    for i, v := range r {
        // runeをバイト列に変換
        // 一旦、runeを文字列にして、そこからバイト列に変換する
        b := []byte(string(v))

        fmt.Printf("rune[%d] %d byte(s)\n", i, len(b))
    }

    // ----------------------------------------------------------
    // runeのスライスを string を経由せずに、直接 byte スライスに変換
    // (https://stackoverflow.com/questions/29255746/how-encode-rune-into-byte-using-utf8-in-golang)
    // ----------------------------------------------------------
    // 予めUtf-8の1文字での最大バイト数分で大きめにバッファを用意しておく
    buf := make([]byte, len(r)*utf8.UTFMax)

    // rune を一つずつエンコード
    count := 0
    for _, v := range r {
        count += utf8.EncodeRune(buf[count:], v)
    }

    // スライスのサイズを調整
    buf = buf[:count]

    fmt.Printf("%s(%v)\n", buf, buf)

    return nil
}

https://github.com/devlights/try-golang/blob/master/basic/string_/string_rune_byte_convert.go

実行結果は以下のような感じ。

[Name] "string_rune_byte_convert"
len(s) == 20
len(r) == 10
rune[0] 3 bytes
rune[1] 3 bytes
rune[2] 3 bytes
rune[3] 3 bytes
rune[4] 3 bytes
rune[5] 1 bytes
rune[6] 1 bytes
rune[7] 1 bytes
rune[8] 1 bytes
rune[9] 1 bytes
こんにちわworld([227 129 147 227 130 147 227 129 171 227 129 161 227 130 143 119 111 114 108 100])

参考情報

stackoverflow.com

golang.org

qiita.com

サンプル書いた後で、上のQiitaの記事を見つけたのですが、こちらの方が100倍詳しく、かつ、わかりやすく書かれていました。


過去の記事については、以下のページからご参照下さい。

  • いろいろ備忘録日記まとめ

devlights.github.io

サンプルコードは、以下の場所で公開しています。

  • いろいろ備忘録日記サンプルソース置き場

github.com

github.com

github.com