Функция utf8.DecodeRune

Функция utf8.DecodeRune декодирует первый символ Unicode (руну) из байтового среза. Она возвращает два значения: декодированную руну и количество байт, которые она заняла. В качестве единственного параметра функция принимает байтовый срез []byte. Если срез начинается с некорректной UTF-8 последовательности, функция возвращает специальную руну utf8.RuneError (которая равна U+FFFD) и значение 1 (один байт считает некорректным).

Синтаксис

goruneValue, size := utf8.DecodeRune(p)

Где p — байтовый срез []byte, с которого начинается декодирование.

Пример

Давайте декодируем первую руну из байтового среза, содержащего строку "Hello":

gopackage main

import (
  "fmt"
  "unicode/utf8"
)

func main() {
  data := []byte("Hello")
  r, size := utf8.DecodeRune(data)

  fmt.Printf("Руна: %q, Размер: %d\n", r, size)
}

Результат выполнения кода:

go"Руна: 'H', Размер: 1"

Мы видим, что латинская буква 'H' занимает 1 байт в UTF-8.

Пример

Теперь давайте декодируем первую руну из байтового среза, содержащего кириллическую строку "Привет":

gopackage main

import (
  "fmt"
  "unicode/utf8"
)

func main() {
  data := []byte("Привет")
  r, size := utf8.DecodeRune(data)

  fmt.Printf("Руна: %q, Размер: %d\n", r, size)
}

Результат выполнения кода:

go"Руна: 'П', Размер: 2"

Буква 'П' в UTF-8 кодируется двумя байтами, что и показывает функция.

Пример

Давайте посмотрим, как функция реагирует на некорректные UTF-8 данные. Предположим, что у нас есть байтовый срез, содержащий неполную последовательность:

gopackage main

import (
  "fmt"
  "unicode/utf8"
)

func main() {
  // Некорректная UTF-8 последовательность (0xC2 - это
  // начало двухбайтовой последовательности, но нет продолжения)
  data := []byte{0xC2}
  r, size := utf8.DecodeRune(data)

  fmt.Printf("Руна: %q, Размер: %d\n", r, size)
}

Результат выполнения кода:

go"Руна: '�', Размер: 1"

В этом случае функция возвращает специальную руну ошибки utf8.RuneError (отображается как '�') и размер 1, указывая на то, что один байт был обработан как некорректный.

Пример

Функция также может быть использована для итерации по всем рунам в байтовом срезе. Давайте пройдемся по строке "Go-язык":

gopackage main

import (
  "fmt"
  "unicode/utf8"
)

func main() {
  data := []byte("Go-язык")

  for i := 0; i < len(data); {
    r, size := utf8.DecodeRune(data[i:])
    fmt.Printf("Руна: %q, позиция: %d\n", r, i)
    i += size
  }
}

Результат выполнения кода:

go"Руна: 'G', позиция: 0"
"Руна: 'o', позиция: 1"
"Руна: '-', позиция: 2"
"Руна: 'я', позиция: 3"
"Руна: 'з', позиция: 5"
"Руна: 'ы', позиция: 7"
"Руна: 'к', позиция: 9"

В этом примере видно, как руны смещаются по позициям: латиница и дефис занимают по 1 байту, а кириллические буквы занимают по 2 байта.

Смотрите также

  • функцию utf8.DecodeRuneInString,
    которая декодирует первую руну из строки
  • функцию utf8.DecodeLastRune,
    которая декодирует последнюю руну из байтового среза
  • функцию utf8.RuneCount,
    которая подсчитывает количество рун в байтовом срезе
  • функцию utf8.Valid,
    которая проверяет, является ли байтовый срез корректным UTF-8