Go言語の文字列ループ処理!runeを使った文字単位の安全な繰り返し方法
生徒
「Go言語で日本語の文字列を1文字ずつ処理したいのですが、どうすればいいですか?」
先生
「文字列は内部的にバイト列として管理されているため、普通のループではマルチバイト文字が正しく扱えません。ここでruneを使う方法が有効です。」
生徒
「runeって何ですか?」
先生
「runeはGoで文字を表す型で、Unicodeのコードポイントを格納します。これを使うと、日本語などのマルチバイト文字も正しく1文字ずつ処理できます。」
1. 文字列のループ処理で注意すること
Go言語では文字列はバイト列として扱われます。そのため、for i := 0; i < len(s); i++のように単純なインデックスでループすると、日本語や絵文字などのマルチバイト文字が途中で切れてしまうことがあります。これを避けるために、rune型を使った文字単位のループが推奨されます。
2. runeを使った基本的なループ
文字列をruneスライスに変換してからループすると、1文字ずつ正確に処理できます。
package main
import "fmt"
func main() {
str := "こんにちは"
for _, r := range str {
fmt.Println(string(r))
}
}
こ
ん
に
ち
は
このようにrangeを使うと、インデックスとruneを同時に取得できます。アンダースコア(_)はインデックスを無視するための書き方です。
3. インデックスも取得する方法
文字の位置も知りたい場合は、rangeでインデックスを取得します。インデックスはバイト単位で返されるので、注意が必要です。
package main
import "fmt"
func main() {
str := "こんにちは"
for i, r := range str {
fmt.Printf("バイト位置 %d: 文字 %s\n", i, string(r))
}
}
バイト位置 0: 文字 こ
バイト位置 3: 文字 ん
バイト位置 6: 文字 に
バイト位置 9: 文字 ち
バイト位置 12: 文字 は
日本語の1文字は複数バイトで表現されるため、バイト位置が3ずつ増えています。これはUTF-8で文字がエンコードされているためです。
4. 文字単位ループの応用例
文字列内の文字を1つずつ処理することで、文字のカウントや特定文字の置換、文字の検証などに活用できます。
package main
import "fmt"
func main() {
str := "Go言語は楽しい"
count := 0
for _, r := range str {
if r == '楽' {
count++
}
}
fmt.Printf("'楽'の出現回数: %d\n", count)
}
'楽'の出現回数: 1
このようにruneを使うことで、文字単位で安全に処理できるため、マルチバイト文字を含む文字列でも正確に操作できます。
5. パフォーマンスを意識した文字列ループ
文字列が非常に長い場合、runeスライスに変換する処理はメモリを使います。頻繁に文字単位で操作する場合は、必要に応じてrangeで直接処理するか、処理の回数を減らすなど工夫しましょう。
6. まとめとしてのポイント
- Go言語の文字列はバイト列で管理されている
- 日本語や絵文字は複数バイトで表現されるので単純ループでは危険
runeを使うと文字単位で安全にループできるrangeでインデックスと文字を取得可能- 長い文字列を扱う場合はメモリとパフォーマンスに注意