2017-01-21 7 views
1

Я читаю раздел for заявления в Effective Go documentation и наткнулся на этот пример:Что определяет положение символа при прохождении через строки UTF-8?

for pos, char := range "日本\x80語" { 
    fmt.Printf("Character %#U, at position: %d\n", char, pos) 
} 

Выход есть:

Character U+65E5 '日', at position: 0 
Character U+672C '本', at position: 3 
Character U+FFFD '�', at position: 6 
Character U+8A9E '語', at position: 7 

То, что я не понимаю, почему позиции 0, 3, 6 и 7. Это говорит о том, что первый и второй символы имеют длину 3 байта, а «замещающая руна» (U + FFFD) - 1 байт, что я принимаю и понимаю. Однако я думал, что rune имеет тип int32 и поэтому будет 4 байта каждый, а не три.

Почему позиции в диапазоне, отличном от общего объема памяти, должны потребляться?

ответ

4

string значение в Go сохраняется только для чтения байта ломтиков ([]byte), где байты являются UTF-8 кодированных байтами (rune й лет) string. UTF-8 - кодирование переменной длины, различные кодовые точки Юникода могут быть закодированы с использованием различного количества байтов. Например, значения в диапазоне 0..127 кодируются как один байт (значение которого является самой кодовой частью юникода), но значения, превышающие 127, используют более 1 байта. Пакет unicode/utf8 содержит служебные функции и константы, связанные с UTF-8, например, utf8.UTFMax сообщает максимальное количество байтов, которое допустимый код Unicode может «занимать» в кодировке UTF-8 (что равно 4).

Одна вещь, чтобы отметить здесь: не все возможные последовательности байт являются допустимыми UTF-8 последовательности. A string может быть любой последовательностью байтов, даже те, которые являются недопустимыми последовательностями UTF-8. Например, значение "\xff"string представляет собой недопустимую последовательность UTF-8 байт, для получения дополнительной информации см How do I represent an Optional String in Go?

for range конструкция -когда наносят на string значение- итерацию над рунами в string:

Для строковое значение, предложение «range» выполняет итерацию по кодовым точкам Unicode в строке, начинающейся с индекса байта 0. При последовательных итерациях значение индекса будет индексом первого байта последовательных кодовых точек с кодировкой UTF-8 в строка, а второе значение типа rune будет значением соответствующей кодовой точки. Если итерация встречает недействительную последовательность UTF-8, второе значение будет 0xFFFD, символ замены Юникода, а следующая итерация будет продвигать один байт в строке.

Конструкция for range может производить 1 или 2 значения итерации. При использовании 2, как в вашем примере:

for pos, char := range "日本\x80語" { 
    fmt.Printf("Character %#U, at position: %d\n", char, pos) 
} 

Для каждой итерации pos будет индекс байт руна/символа, и char будет руна string.Как вы можете видеть в приведенной выше цитате, если string является недопустимой последовательностью байтов UTF-8, когда встречается некорректная последовательность UTF-8, char будет 0xFFFD (символ замены Юникода) и for range (итерация) будет продвигать только байт только.

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

нужно прочитать сообщение в блоге, если вы хотите узнать больше об этой теме:

The Go Blog: Strings, bytes, runes and characters in Go

+0

Это сообщение в блоге было очень полезным, и я рекомендую всем, у кого есть аналогичный запрос, прочитать его. Я думаю, что моя путаница заключалась в том, что «диапазон» совершил какое-то неявное преобразование в кусок рун, когда на самом деле это не так. Спасибо. – HenryTK

0

rune является точкой коды. Точка кода просто целое. Вы можете даже использовать int64, чтобы сохранить его, если хотите. (Но Unicode имеет только 1,114,112 код точки так int32 должен быть правильным выбором. Не удивительно, что rune не является псевдонимом int32 в Golang.)

Различные схемы кодирования кодирования кодовых точек по-разному. Например. Символ CJK обычно кодируется в 3 байта в UTF-8 и до 2 байтов в UTF-16.

Строковый литерал в Голанге - UTF-8.

 Смежные вопросы

  • Нет связанных вопросов^_^