← Назад к вопросам

При помощи какого пакета можно узнать число символов в строке в Go

2.2 Middle🔥 122 комментариев
#Другое

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Работа со строками в Go: длина в символах (рунах) vs байтах

В Go для определения длины строки в байтах используется встроенная функция len(), но это НЕ дает число символов для строк Unicode. Для корректного подсчета символов (рун) необходимо использовать пакет unicode/utf8 и функцию utf8.RuneCountInString().

Основное различие: байты vs руны

package main

import (
	"fmt"
	"unicode/utf8"
)

func main() {
	str := "Привет, мир!" // Кириллица + ASCII
	
	// 1. Длина в байтах (неправильно для подсчета символов)
	byteLength := len(str)
	fmt.Printf("Длина в байтах: %d\n", byteLength) // Вывод: 20 (не 12!)
	
	// 2. Длина в символах (рунах) - ПРАВИЛЬНЫЙ СПОСОБ
	runeCount := utf8.RuneCountInString(str)
	fmt.Printf("Число символов (рун): %d\n", runeCount) // Вывод: 12
	
	// 3. Альтернатива: конвертация в []rune (менее эффективно)
	runeSlice := []rune(str)
	fmt.Printf("Длина через []rune: %d\n", len(runeSlice)) // Вывод: 12
}

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

Go использует кодировку UTF-8, где символы могут занимать от 1 до 4 байт:

  • ASCII символы: 1 байт
  • Кириллица: 2 байта
  • Сложные иероглифы, эмодзи: 3-4 байта
str1 := "A"           // 1 байт
str2 := "Ж"           // 2 байта  
str3 := "😀"          // 4 байта
str4 := "é"          // 2 руны, 3 байта (комбинированный символ)

fmt.Println(len(str1), len(str2), len(str3), len(str4)) // 1 2 4 3
fmt.Println(utf8.RuneCountInString(str1), 
            utf8.RuneCountInString(str2),
            utf8.RuneCountInString(str3),
            utf8.RuneCountInString(str4)) // 1 1 1 2

Когда использовать каждый подход?

utf8.RuneCountInString() (рекомендуется для подсчета символов):

  • Подсчет видимых символов в UI
  • Валидация длины текста для пользователя
  • Обработка текста на естественных языках
  • Работа с многоязычными строками
// Пример: проверка максимальной длины комментария
func validateComment(comment string, maxLength int) bool {
    return utf8.RuneCountInString(comment) <= maxLength
}

len() (длина в байтах):

  • Работа с бинарными данными
  • Выделение буферов фиксированного размера
  • Сетевые протоколы, где важны байты
  • Чтение/запись файлов
// Пример: подготовка буфера для сетевой отправки
func prepareBuffer(data string) []byte {
    buffer := make([]byte, len(data)+4) // +4 для заголовка
    // ... копирование данных
    return buffer
}

Дополнительные возможности unicode/utf8

Пакет предоставляет и другие полезные функции:

import "unicode/utf8"

// Проверка валидности UTF-8
valid := utf8.ValidString(str)

// Декодирование первой руны
r, size := utf8.DecodeRuneInString(str)

// Итерация по рунам
for i, r := range str {
    fmt.Printf("Руна %d: %c (код: %U)\n", i, r, r)
}

// Альтернативная итерация
for i := 0; i < len(str); {
    r, size := utf8.DecodeRuneInString(str[i:])
    fmt.Printf("Руна начинается с байта %d: %c\n", i, r)
    i += size
}

Производительность и рекомендации

  • utf8.RuneCountInString() работает за O(n), пробегая по всем байтам строки
  • Конвертация в []rune также требует O(n) плюс выделение памяти
  • Для многократных операций лучше конвертировать один раз в []rune:
// НЕЭФФЕКТИВНО (двойной обход)
for i := 0; i < utf8.RuneCountInString(str); i++ {
    // ...
}

// ЭФФЕКТИВНО
runes := []rune(str)
for i := 0; i < len(runes); i++ {
    // Обработка runes[i]
}

Особые случаи и предостережения

  1. Комбинированные символы: utf8.RuneCountInString() считает каждый рунный код отдельно

    "café"    // 4 руны (e + acute accent раздельно)
    "cafe\u0301" // То же самое, 5 байт, 4 руны
    
  2. Для графемных кластеров (emoji с модификаторами кожи, флаги) нужны дополнительные библиотеки:

    "👨‍👩‍👧‍👦" // 1 семья, но 7 рун и 25 байт!
    

Вывод

Для определения числа символов в строке в Go используйте utf8.RuneCountInString() из пакета unicode/utf8. Функция len() возвращает только количество байт, что для UTF-8 строк не соответствует числу символов. Выбор метода зависит от контекста: для пользовательского текста — подсчет рун, для низкоуровневых операций — работа с байтами.

При помощи какого пакета можно узнать число символов в строке в Go | PrepBro