カテゴリ: Go言語 更新日: 2025/12/25

Go言語で文字列のエンコーディングを理解!UTF-8の基本を初心者向けに解説

Go言語の文字列操作におけるエンコーディング(UTF-8など)の基本
Go言語の文字列操作におけるエンコーディング(UTF-8など)の基本

先生と生徒の会話形式で理解しよう

生徒

「Go言語で文字列を扱うとき、エンコーディングって何ですか?」

先生

「エンコーディングとは、文字をコンピュータが理解できる数字の形に変換するルールのことです。Go言語では基本的にUTF-8という方式を使っています。」

生徒

「UTF-8って聞いたことあります。具体的にはどんなものなんですか?」

先生

「UTF-8は、世界中のほとんどの文字を表現できる方式で、1文字が1〜4バイトで表されます。ASCII文字は1バイト、日本語などの文字は複数バイトで表現されます。」

生徒

「なるほど!Goで文字列を扱うときは、いつもUTF-8で保存されているんですね?」

先生

「その通りです。UTF-8を理解すると、文字列操作やバイトスライスの扱い方もより理解しやすくなります。」

1. Go言語の文字列はUTF-8で保存される

1. Go言語の文字列はUTF-8で保存される
1. Go言語の文字列はUTF-8で保存される

Go言語の文字列は、内部的にUTF-8で保存されます。UTF-8は可変長のエンコーディング方式で、英数字は1バイト、日本語などのマルチバイト文字は2〜4バイトで表現されます。この仕組みを理解すると、文字列の長さや文字単位の操作が重要であることがわかります。

2. 文字列の長さとバイト数の違い

2. 文字列の長さとバイト数の違い
2. 文字列の長さとバイト数の違い

UTF-8では、文字列の長さとバイト数は一致しないことがあります。英語の文字は1バイト、日本語の文字は3バイト程度になることが多いです。そのため、len()関数で取得できるのはバイト数で、文字数ではありません。


package main

import (
    "fmt"
)

func main() {
    str := "Go言語"
    fmt.Println("バイト数:", len(str))
}

バイト数: 8

上記の例では、日本語2文字と英字1文字で構成されていますが、バイト数は8になります。これはUTF-8で日本語1文字が3バイトで表現されるためです。

3. 文字単位で扱うにはrune型を使う

3. 文字単位で扱うにはrune型を使う
3. 文字単位で扱うにはrune型を使う

文字単位で操作したい場合、Goではrune型を使います。runeはUnicodeコードポイントを表す型で、1文字ごとに扱うことができます。


package main

import (
    "fmt"
)

func main() {
    str := "Go言語"
    for i, r := range str {
        fmt.Printf("インデックス %d: %c\n", i, r)
    }
}

インデックス 0: G
インデックス 1: o
インデックス 3: 言
インデックス 6: 語

インデックスがバイト単位で表示されることに注意してください。runeを使うと、文字単位で正確に処理できます。

Go言語を基礎からスッキリ学びたい人や、 文法だけでなく「実用的な使い方」まで押さえたい人には、 定番の入門書がこちらです。

基礎からわかるGo言語をAmazonで見る

※ Amazon広告リンク

4. バイトスライスとの関係

4. バイトスライスとの関係
4. バイトスライスとの関係

文字列をバイトスライスに変換すると、UTF-8でエンコードされたバイト列として扱えます。バイト単位での処理や、ファイルへの書き込み、ネットワーク通信などに便利です。


package main

import (
    "fmt"
)

func main() {
    str := "Go言語"
    b := []byte(str)
    fmt.Println(b)
}

[71 111 230 149 136 232 170 158]

英字は1バイト、日本語はUTF-8で3バイトずつに変換されていることがわかります。

5. ポイント整理

5. ポイント整理
5. ポイント整理

Go言語では文字列はUTF-8で保存され、len()で取得できるのはバイト数です。文字単位で操作する場合はrune型を使い、バイト単位で処理する場合は[]byte型を使用します。UTF-8の仕組みを理解すると、日本語や特殊文字を含む文字列の操作も安全に行えます。

6. 文字列のインデックスアクセスで注意する点

6. 文字列のインデックスアクセスで注意する点
6. 文字列のインデックスアクセスで注意する点

Go言語の文字列はUTF-8で保存されているため、インデックスを使って直接アクセスする場合は注意が必要です。str[0]のような書き方で取得できるのは「文字」ではなく「バイト」です。英字であれば問題ありませんが、日本語などのマルチバイト文字では、意図しない値になることがあります。


package main

import "fmt"

func main() {
    str := "Go言語"
    fmt.Println(str[0])
}

71

この出力結果は文字ではなく、UTF-8でエンコードされたバイト値です。文字として扱いたい場合は、インデックスアクセスではなくrunefor rangeを使うのが安全です。

7. 文字列をスライスするときの考え方

7. 文字列をスライスするときの考え方
7. 文字列をスライスするときの考え方

Go言語では、文字列もスライスのように一部を切り出すことができます。ただし、この操作もバイト単位で行われるため、日本語を含む文字列では注意が必要です。途中のバイトで切り出すと、文字が壊れてしまう可能性があります。


package main

import "fmt"

func main() {
    str := "Go言語"
    fmt.Println(str[:2])
}

Go

この例では英字部分だけを切り出しているため問題ありませんが、日本語部分を含めてスライスすると正しく表示されないことがあります。文字単位で安全に切り出したい場合は、一度[]runeに変換してから処理する方法がよく使われます。

8. UTF-8を意識することで防げるトラブル

8. UTF-8を意識することで防げるトラブル
8. UTF-8を意識することで防げるトラブル

UTF-8の仕組みを理解していないと、「文字数制限が合わない」「入力チェックでエラーになる」「画面表示が崩れる」といったトラブルが起きやすくなります。特に日本語を扱うWebアプリケーションや業務システムでは、文字数とバイト数の違いを意識することが重要です。

Go言語では、文字列・rune[]byteという3つの視点を使い分けることで、こうした問題を未然に防ぐことができます。最初は少し難しく感じるかもしれませんが、UTF-8を前提とした考え方に慣れることで、文字列処理への理解が一段と深まります。

まとめ

まとめ
まとめ

Go言語の文字列とUTF-8エンコーディングを振り返る

この記事では、Go言語における文字列のエンコーディングの基本として、UTF-8の考え方を中心に解説してきました。 Go言語の文字列は、内部的にすべてUTF-8で保存されており、この前提を理解することが文字列処理の第一歩になります。 UTF-8は世界中の文字を扱える柔軟なエンコーディング方式で、英数字は1バイト、日本語や記号などは複数バイトで表現されます。 この仕組みを知らないまま文字列を操作すると、「文字数が合わない」「途中で文字が壊れる」といった問題に直面しやすくなります。

特に重要なのは、Go言語のlen()関数が返す値は「文字数」ではなく「バイト数」であるという点です。 英語だけの文字列であれば、文字数とバイト数は同じになるため違和感がありませんが、 日本語や全角文字を含む場合は、見た目の文字数とlen()の結果が大きく異なります。 そのため、画面表示や文字数制限、入力チェックなどを行う場面では、 「今扱っているのはバイトなのか、それとも文字なのか」を常に意識することが大切です。

runeとbyteを正しく使い分ける考え方

Go言語では、文字単位で扱いたい場合にrune型を使います。 runeはUnicodeのコードポイントを表す型で、1文字ずつ安全に処理できるのが特徴です。 for range構文で文字列をループすると、自動的にrune単位で処理されるため、 日本語を含む文字列でも安心して1文字ずつ取り出せます。 一方で、インデックスがバイト単位で進む点は、初学者が混乱しやすいポイントでもあります。

反対に、ファイル操作やネットワーク通信、バイナリデータの処理などでは、 文字ではなくバイト単位での扱いが必要になります。 その場合は、文字列を[]byteに変換して処理するのが一般的です。 Go言語では文字列とバイトスライスの相互変換が簡単にできるため、 「文字として扱うのか」「データとして扱うのか」という目的に応じて型を選ぶことが重要になります。

振り返り用サンプルプログラム

ここで、UTF-8と文字列の扱いをもう一度整理するために、 バイト数と文字単位の違いが分かるシンプルなサンプルプログラムを見てみましょう。


package main

import (
    "fmt"
)

func main() {
    str := "Go言語"

    fmt.Println("バイト数:", len(str))

    count := 0
    for range str {
        count++
    }
    fmt.Println("文字数:", count)
}

この例では、len()で取得したバイト数と、 for rangeを使って数えた文字数が異なることを確認できます。 実際の開発では、この違いを理解しているかどうかが、 文字列処理の正確さに大きく影響します。

先生と生徒の振り返り会話

生徒

「lenで取れるのが文字数じゃなくてバイト数だっていうのは、 正直かなり意外でした。」

先生

「多くの人が最初につまずくポイントですね。 でもUTF-8の仕組みを知っていれば、自然な仕様だと分かります。」

生徒

「文字単位で扱いたいときはrune、 データとして扱いたいときはbyteという使い分けが大事なんですね。」

先生

「その理解で完璧です。 UTF-8とGo言語の文字列の特徴を押さえておけば、 日本語を含むプログラムでも安心して開発できますよ。」

カテゴリの一覧へ
新着記事
New1
Go言語
Go言語の構造体の初期化パターンとコンストラクタ的関数の書き方を徹底解説!初心者でもわかる基本と実用例
New2
Kotlin
Kotlinの例外処理とキャンセルの連携を完全ガイド!初心者でもわかるCoroutineExceptionHandlerの使い方
New3
Go言語
Go言語のクロージャとは?関数内関数の活用例と仕組み
New4
Swift
Swiftでエラー原因を可視化!ログとトレースのベストプラクティスを初心者向けに解説
人気記事
No.1
Java&Spring記事人気No1
Kotlin
KotlinのChannelでデータをやり取りする方法を完全ガイド!初心者にもわかる非同期通信の基本
No.2
Java&Spring記事人気No2
Go言語
Go言語でのDB接続情報を環境変数で管理する方法|初心者でも安全に設定
No.3
Java&Spring記事人気No3
Kotlin
Android Studioのインストール手順と初期設定を初心者向けに完全解説!
No.4
Java&Spring記事人気No4
Kotlin
Kotlinのビルド設定エラーと解決法まとめ!初心者向けGradleトラブル対処ガイド
No.5
Java&Spring記事人気No5
Kotlin
Gradleファイル(build.gradle.kts)の書き方と役割をやさしく解説!Kotlin初心者向け完全ガイド
No.6
Java&Spring記事人気No6
Kotlin
Kotlinでテキスト表示・編集!初心者でもわかるTextViewとEditTextの使い方
No.7
Java&Spring記事人気No7
Swift
Swift Playgroundの使い方を完全解説!初心者に最適な学習環境の始め方
No.8
Java&Spring記事人気No8
Go言語
Go言語のgo.modファイル完全ガイド!初心者でもわかる仕組みと書き方

💻 作業効率アップに

ノートPCを縦置きしてデスクを広く。
省スペースで片づく定番スタンド

UGREEN 縦型スタンドをAmazonで見る

※ Amazon広告リンク