Максимальный размер строки UTF-8 с учетом размера UTF-16 - PullRequest
1 голос
/ 08 марта 2019

Какова формула для определения максимального количества байтов UTF-8, необходимого для кодирования заданного количества кодовых единиц UTF-16 (т. Е. Значения String.Length в C # / .NET)?

Я вижу 3 варианта:

1) # of UTF-16 code units x 2

2) # of UTF-16 code units x 3

3) # of UTF-16 code units x 4

Кодовая точка UTF-16 представлена ​​1 или 2 единицами кода, поэтому нам просто нужно рассмотреть сценарий наихудшего случая для строки, заполненной одной или другой. Если строка UTF-16 полностью состоит из 2 кодовых точек кодовой единицы, то мы знаем, что представление UTF-8 будет максимально одного размера, поскольку кодовые точки занимают максимум 4 байта в обоих представлениях, таким образом, наихудший случай вариант (1) выше.

Таким образом, интересный случай, на который я не знаю ответа, - это максимальное количество байтов, которое может потребоваться для одной кодовой единицы UTF-16 в представлении UTF-8.

Если все кодовые точки UTF-16 с одной кодовой единицей могут быть представлены 3 байтами UTF-8, что, как мне подсказывает моя интуиция, наиболее целесообразно, тогда вариант (2) будет сценарием наихудшего случая. Если есть такие, которые требуют 4 байта, то вариант (3) будет ответом.

У кого-нибудь есть понимание, что является правильным? Я действительно надеюсь на (1) или (2), так как (3) все усложнит: /

UPDATE

Я далеко не эксперт по UTF, но из того, что я могу собрать, UTF-16 кодирует все символы в BMP в одной кодовой единице, а все остальные плоскости кодируются в 2 кодовых единицах.

Кажется, что UTF-8 может кодировать весь BMP в пределах 3 байтов и использует 4 байта для кодирования других плоскостей.

Таким образом, мне кажется, что вариант (2) выше является правильным ответом, и это должно сработать:

string str = "Some string";
int maxUtf8EncodedSize = str.Length * 3;

Похоже, это подтвердилось?

1 Ответ

3 голосов
/ 08 марта 2019

Правильно сформированный UTF-8 может содержать до 4 байтов на кодовую точку Unicode.

Символы в кодировке UTF-16 могут содержать до 2 16-битных последовательностей на кодовую точку Unicode.

Символы вне базовой многоязычной плоскости (включая эмодзи и языки, которые были добавлены в более поздние версии Unicode) представлены до 21 бита, что в формате UTF-8 приводит к 4-байтовым последовательностям, которые также занимают 4 байта в UTF-16.

Однако, есть некоторые среды, которые делают вещи странно. Поскольку символы UTF-16 вне базовой многоязычной плоскости занимают до 2 16-битных последовательностей (они могут быть обнаружены, потому что они всегда 16-битные последовательности в диапазоне от U + D800 до U + DFFF), некоторые ошибочные реализации UTF-8, обычно называемый CESU-8, который преобразует эти последовательности UTF-8 в две 3-байтовые последовательности UTF-8, что в сумме составляет шесть байтов на кодовую точку UTF-32. (Я полагаю, что некоторые ранние реализации БД Oracle делали это, и я уверен, что они были не единственными).

Есть еще один незначительный ключ в том, что некоторые глифы классифицируются как объединяющие символы, и несколько последовательностей UTF-16 (или UTF-32) используются при определении того, что отображается на экране, но я не думаю, что это применимо в вашем случае.

Исходя из ваших правок, похоже, что вы пытаетесь оценить максимальную длину преобразования кодировки .Net. Длина строки измеряет общее количество символов, которые являются количеством кодовых точек UTF-16. Поэтому, как наихудшая оценка, я полагаю, что вы можете безошибочно оценить количество (Char) * 3, потому что не-BMP символы будут считать (Char) * 2, получая 4 байта как UTF-8.

Если вы хотите получить общее количество представленных кодовых точек UTF-32, вы можете сделать что-то вроде

var maximumUtf8Bytes = System.Globalization.StringInfo(myString).LengthInTextElements * 4;

(Мой C # немного заржавел, так как в последние несколько лет я почти не пользовался средой .Net, но думаю, что сработает).

...