Какие есть варианты подсчёта количества символов в строке на Go?

Три разных длины строки: байты, Unicode-кодовые точки и графемные кластеры; примеры кириллицы, комбинируемого акцента и семейного эмодзи.

Короткий ответ

Что ответить на собеседовании

len(s) считает байты, utf8.RuneCountInString(s) — руны при UTF-8-декодировании, а uniseg.GraphemeClusterCount(s) — графемные кластеры. «Привет» занимает 12 байт и содержит 6 рун. e с комбинируемым акцентом — 2 руны, но 1 графема. Выбор зависит от того, что требуется ограничить: размер данных, кодовые точки или воспринимаемые пользователем символы.

Подробный разбор

Ответ с пояснениями

Сначала уточните, что означает «символ». У одной строки могут быть разные корректные значения длины.

Байты: 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, поддерживаемую библиотекой; для лимита размера данных оставляйте подсчёт байтов.

Практика в реальном времени

Подготовьтесь к следующему собеседованию

Interview Boost учитывает вакансию, резюме и технологии и помогает сформулировать ответ прямо во время интервью.

Начать подготовку