Как в Go правильно посчитать количество символов (рун) в строке?

Ответ

Для корректного подсчета символов (рун) в строке, особенно если она содержит кириллицу или другие многобайтовые символы (например, emoji), необходимо использовать пакет unicode/utf8.

Почему len() не подходит?

В Go строка — это последовательность байт. Встроенная функция len() возвращает именно количество байт, а не символов. Поскольку символы в кодировке UTF-8 могут занимать от 1 до 4 байт, len() даст неверный результат для не-ASCII строк.

  • len("abc") вернет 3 (3 символа, 3 байта).
  • len("Привет") вернет 12 (6 символов, 12 байт, т.к. каждая буква кириллицы занимает 2 байта).

Правильный способ: utf8.RuneCountInString()

Эта функция специально предназначена для подсчета рун (кодовых точек Unicode) в строке.

import (
    "fmt"
    "unicode/utf8"
)

func main() {
    s := "Привет, мир! 👋"

    // Неправильный способ
    fmt.Printf("Количество байт (len): %dn", len(s))

    // Правильный способ
    fmt.Printf("Количество символов (рун): %dn", utf8.RuneCountInString(s))
}
// Вывод:
// Количество байт (len): 21
// Количество символов (рун): 15

Итерация по строке

Для перебора символов строки также следует использовать конструкцию for ... range. Она автоматически декодирует UTF-8 символы в руны.

for index, r := range "Привет" {
    // index - начальная позиция байта руны
    // r - сама руна (тип rune, который является псевдонимом для int32)
    fmt.Printf("индекс: %d, символ: %cn", index, r)
}