IT заметки по программированию
IT заметки по программированию
IT заметки по программированию
IT заметки по программированию

Как Golang понимает где какая руна в строке, если у рун может быть разное количество байт?

Go понимает, где заканчивается каждая руна в строке, благодаря тому, что строки в Go представляют собой последовательности байт в кодировке UTF-8. UTF-8 — это переменная длина кодировки, где каждому символу (или кодовой точке Unicode) может соответствовать от 1 до 4 байтов.

Для корректной обработки строк, Go использует принцип, при котором каждую руну можно однозначно определить по начальному байту, а длина руны определяется на основе первых байтов.

Как Go понимает, где заканчивается каждая руна в строке:

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

  1. UTF-8 структура байтов:
    • Один байт: символы с кодами от U+0000 до U+007F (ASCII-символы).
    • Два байта: символы с кодами от U+0080 до U+07FF.
    • Три байта: символы с кодами от U+0800 до U+FFFF.
    • Четыре байта: символы с кодами от U+10000 до U+10FFFF.
  2. Как Go определяет, где заканчивается руна:
    • Каждый символ в UTF-8 начинается с определённой маски, которая указывает, сколько байт он занимает.
      • Для 1 байта (0xxxxxxx): это обычный ASCII символ.
      • Для 2 байтов (110xxxxx 10xxxxxx): маски показывают, что руна начинается с первого байта, который начинается с 110, и следующий байт будет начинаться с 10.
      • Для 3 байтов (1110xxxx 10xxxxxx 10xxxxxx): аналогично для символов, которые требуют 3 байта.
      • Для 4 байтов (11110xxx 10xxxxxx 10xxxxxx 10xxxxxx): для символов, которые требуют 4 байта.
  3. Алгоритм: Go использует эти маски, чтобы распознать, когда заканчивается руна и перейти к следующей. Например, если первый байт начинается с 0xxx xxxx, то это один байт, если с 110x xxxx, то это начало двухбайтового символа, и так далее.

Пример на Go: как Go обрабатывает строки с разными рунными длинами

Когда вы используете range для итерации по строке в Go, он автоматически распознаёт, где заканчивается каждая руна, и правильно её извлекает, независимо от количества байтов.

Пример:

Вывод:

Здесь Go корректно понимает, что символы и занимают по 3 байта (UTF-8), а остальная строка состоит из обычных ASCII-символов, которые занимают по 1 байту.


Важность масок для понимания разной длины байтов

Когда Go читает строку, он использует первую часть каждого байта для того, чтобы понять, сколько байтов требуется для символа. Например:

  • Если первый байт строки начинается с 0xxxxxxx, то это один байт.
  • Если начинается с 110xxxxx, то это начало двухбайтового символа.
  • Если с 1110xxxx, то это начало трёхбайтового символа, и так далее.

Это позволяет Go правильно обрабатывать строки, состоящие как из однобайтовых символов (например, ASCII), так и из многобайтовых символов Unicode.


Итерация через range

Когда мы используем конструкцию range для итерации по строкам в Go, каждый символ в строке автоматически трактуется как руна, независимо от того, сколько байт она занимает. range будет правильно «пропускать» нужное количество байтов для каждого символа и переходить к следующему.


Пример с различными длинами рун:

Вывод:
Здесь видно, что Go правильно обрабатывает каждый символ, независимо от его размера в байтах. Он сдвигает индекс на соответствующее количество байт, чтобы правильно извлечь каждую руну.


Заключение

Go использует UTF-8 для строк, где символы могут иметь разную длину в байтах. Когда вы итерируете по строке с помощью range, Go использует маски в байтах, чтобы правильно идентифицировать, где заканчивается одна руна и начинается следующая. Это позволяет Go эффективно работать с многобайтовыми символами и кодовыми точками Unicode.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *