len(s) считает байты, utf8.RuneCountInString(s) — руны при UTF-8-декодировании, а uniseg.GraphemeClusterCount(s) — графемные кластеры. «Привет» занимает 12 байт и содержит 6 рун. e с комбинируемым акцентом — 2 руны, но 1 графема. Выбор зависит от того, что требуется ограничить: размер данных, кодовые точки или воспринимаемые пользователем символы.
Какие есть варианты подсчёта количества символов в строке на Go?
Три разных длины строки: байты, Unicode-кодовые точки и графемные кластеры; примеры кириллицы, комбинируемого акцента и семейного эмодзи.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Сначала уточните, что означает «символ». У одной строки могут быть разные корректные значения длины.
Байты: len(s) возвращает размер строки в байтах. Это подходит для ограничений протокола или буфера, но не обязательно совпадает с количеством букв. Go string — последовательность байтов, которая не обязана содержать корректный UTF-8. Спецификация Go.
Руны: utf8.RuneCountInString(s) считает результат UTF-8-декодирования, то есть для корректного текста — Unicode-кодовые точки. Можно также считать итерации for range или использовать len([]rune(s)), однако создавать rune-срез только ради длины обычно незачем. rune не обязательно соответствует одному видимому символу. Пакет unicode/utf8.
Графемные кластеры: для пользовательского текста часто нужна сегментация по Unicode UAX #29. Например, библиотека uniseg объединяет базовую букву с комбинируемым акцентом и поддерживаемые последовательности эмодзи в кластеры.
package main
import (
"fmt"
"unicode/utf8"
"github.com/rivo/uniseg"
)
func main() {
for _, s := range []string{"Привет", "e\u0301", "👨👩👧👦"} {
fmt.Println(len(s),
utf8.RuneCountInString(s),
uniseg.GraphemeClusterCount(s))
}
}
Порядок чисел: байты, руны, графемные кластеры.
12 6 6
3 2 1
25 7 1
Во второй строке буква e и акцент представлены отдельно, в третьей четыре эмодзи соединены тремя zero-width joiner. Подсчёт графем не равен ширине текста в пикселях или ячейках терминала.
Если вход может содержать некорректный UTF-8, используйте utf8.ValidString и определите политику обработки ошибки. RuneCountInString не отклоняет такой ввод: некорректные последовательности учитываются с продвижением по одному байту. Для пользовательского лимита выбирайте графемы осознанно и фиксируйте версию Unicode, поддерживаемую библиотекой; для лимита размера данных оставляйте подсчёт байтов.