【Go言語学習|豆知識】Go言語における文字列操作の要!rune型の正しい理解と使い方

導入

Go言語で文字列を扱う際、何気なくstring型を使っていると、日本語などのマルチバイト文字を操作する場面で予期せぬバグに遭遇することがあります。「文字数」を数えたいだけなのにバイト数でカウントしてしまったり、特定の文字を置換しようとして文字列を破壊してしまったりといった経験はありませんか?これらの課題を解決し、正しく文字列を扱うために不可欠なのが「rune型」です。今回は、Goの内部構造を理解するための第一歩として、rune型の仕組みを解説します。

基礎知識

Goにおける文字列(string)は、本質的に「バイト(uint8)の読み取り専用スライス」です。ASCII文字のように1バイトで表現できる文字なら問題ありませんが、日本語などのマルチバイト文字は、1文字を表現するのに3バイト以上を必要とします。

ここで登場するのが「rune型」です。runeは「int32」の別名(エイリアス)であり、Unicodeの「コードポイント」を保持します。つまり、stringが「バイトの羅列」であるのに対し、runeは「文字そのもの」を指し示す型と言えます。

実装/解決策

文字列に対してループ処理を行う際、単純にインデックスでアクセスすると「バイト単位」での操作になってしまいます。文字単位で処理を行いたい場合は、文字列を一度runeのスライスに変換するか、rangeキーワードを使用するのが鉄則です。rangeを使うと、内部で自動的にUnicodeデコードが行われ、バイトではなくrune単位で値を取り出すことができます。

サンプルプログラム

以下のコードは、文字列の長さ(文字数)を正しくカウントし、各文字をruneとして処理する例です。

package main

import (
“fmt”
)

func main() {
// 日本語を含む文字列を定義
str := “Go言語”

// string型のままlenを使うと「バイト数」が返るため、日本語では6バイト(UTF-8)となる
fmt.Printf(“バイト数: %d\n”, len(str))

// runeスライスに変換することで「文字数」として扱えるようになる
runes := []rune(str)
fmt.Printf(“文字数: %d\n”, len(runes))

// rangeを使うと安全にrune単位でループできる
fmt.Println(“文字ごとのコードポイント:”)
for i, r := range str {
// r は rune型(int32)として取得される
fmt.Printf(“インデックス %d: 文字 %c (コードポイント: %U)\n”, i, r, r)
}
}

応用・注意点

現場での開発において、特に注意すべきは「文字数制限」のバリデーションです。データベースのカラム制限などで文字数をチェックする際は、必ずlen(string)ではなく、[]runeに変換した後の長さを使用してください。

また、rune型は「1つのUnicodeコードポイント」を表しますが、厳密には「書記素(人が見て1文字と認識する単位)」とは異なる場合があります。例えば、濁点付きの文字などは、Unicode上では「文字本体」+「濁点」のように複数のコードポイントで構成されることがあります。より厳密なテキスト処理が必要な場合は、標準ライブラリの「golang.org/x/text/unicode/norm」パッケージなどを使用して正規化を行うことも検討しましょう。まずは基本であるruneをマスターし、安全な文字列操作を心がけてください。

コメント

タイトルとURLをコピーしました