文字コード周辺についてGo絡めてまとめてみた

こんにちは。主にバックエンドを担当している関口です。 HRBrainAdventCalendar 14日目の記事です。前日の夜から記事に取り掛かったので、過去に調べてGitHubにメモしていた物を記事にしました。GitHubのメモはこちら

そもそもの文字コード周辺の単語の整理

  • 文字コード

    • コンピュータ上で文字(キャラクタ)を利用する目的で各文字に割り当てられるバイト表現。もしくは、バイト表現と文字の対応関係(文字コード体系)のこと

  • 文字集合

    • 文字を重複なく集めた集合

      • 引用元 : 矢野 啓介 (2018/12/28)『[改訂新版]プログラマのための文字コード技術入門 (WEB+DB PRESS plusシリーズ) 単行本』技術評論社
  • 符号化文字集合

    • 文字集合を定義し、その集合の各文字に対応するビット組み合わせを一意に定めたもの

      • 引用元 : 矢野 啓介 (2018/12/28)『[改訂新版]プログラマのための文字コード技術入門 (WEB+DB PRESS plusシリーズ) 単行本』技術評論社
  • 符号化方式

ざっくり言うと、文字コードは以下の2段階に区別することができる感じです。

  • 符号化文字集合で、扱いたい文字を集めた物(文字集合)とその文字集合の各々の文字に対応するビット組み合わせを決める
  • 符号化方式で、実際に符号化文字集合を組み合わせたりして、コンピュータが利用できる形に変換する運用する方式を決める

参考

Goの文字コードの話とrune

  • Unicodeは、符号化文字集合
    • コードポイントは、符号化文字集合内で文字に割り当てるための場所
  • UTF-8は、符号化方式
  • Goのソースコードや文字列リテラルは、UTF-8
  • Goのruneは、Unicode(符号化文字集合)のコードポイント

参考

Goで文字コードを変換してみる

こちらの記事 を参考に以下のようなコードを書いてみました。(playgroundでも書いている)

package main

import (
    "fmt"
    "io/ioutil"
    "strings"

    "golang.org/x/text/encoding/japanese"
    "golang.org/x/text/transform"
)

func main() {
    a := "abc"
    a2, err := convertFromUTF8ToShiftJis(a)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Printf("a2 = %v, len = %d\n", a2, len(a2))

    b := "あいう"
    b2, err := convertFromUTF8ToShiftJis(b)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Printf("b2 = %v, len = %d\n", b2, len(b2))

    c := "🙇<200d>♀️" // 普通に絵文字だけ書いているのですが、はてなで表示する際には 「<200d>♀️」が付与されてしまいます。元々のコードをみたい場合には、https://play.golang.org/p/hb_LGte3dkV をご覧ください。
    c2, err := convertFromUTF8ToShiftJis(c)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Printf("c2 = %v, len = %d\n", c2, len(c2))
}

func convertFromUTF8ToShiftJis(str string) (string, error) {
    iostr := strings.NewReader(str)
    rio := transform.NewReader(iostr, japanese.ShiftJIS.NewEncoder())
    ret, err := ioutil.ReadAll(rio)
    if err != nil {
        return "", err
    }
    return string(ret), err
}

b2, err := convertFromUTF8ToShiftJis(b) の際には、 rune not supported by encoding. のエラーを返します。 これはなぜかというと、

  • Shift_JIS は符号化文字集合として、JIS X 0208を使用していて
  • JIS X 0208 では、その文字集合の表の中に絵文字が存在していないため
    • ただし、Shift_JISでも、絵文字を表示できたりする場合がある
      • JIS X 0208 の外字である絵文字を文字集合の表の空き領域内に定義して使用しているから
        • 文字集合に含まれない文字を 外字 と言う

参考文献

  • 矢野 啓介 (2018/12/28)『[改訂新版]プログラマのための文字コード技術入門 (WEB+DB PRESS plusシリーズ) 単行本』技術評論社

参考にさせていただいたサイト