Как преобразовать суррогатную пару в Unicode скаляр в Swift
Следующий пример взят из Документация строк и символов:
![enter image description here]()
Значения 55357
(U+D83D
в шестнадцатеричном формате) и 56374
(U+DC36
в шестнадцатеричном виде) являются суррогатными парами, которые формируют скаляр Unicode U+1F436
, который является символом DOG FACE
. Есть ли способ пойти в другую сторону? То есть, могу ли я преобразовать суррогатную пару в скаляр?
Я пробовал
let myChar: Character = "\u{D83D}\u{DC36}"
но я получил ошибку "Неверный Unicode скалярный".
Этот ответ Objective C и этот проект, по-видимому, являются обычными решениями, но есть ли что-нибудь встроенное в Swift (особенно Swift 2.0+), которое это делает?
Ответы
Ответ 1
Существуют формулы для вычисления исходной кодовой точки на основе суррогатной пары и наоборот. Из https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae:
Раздел 3.7 Стандарта Unicode 3.0 определяет алгоритмы преобразования в суррогатные пары и из них.
Кодовая точка C
больше, чем 0xFFFF
соответствует суррогатной паре <H, L>
согласно следующей формуле:
H = Math.floor((C - 0x10000) / 0x400) + 0xD800
L = (C - 0x10000) % 0x400 + 0xDC00
Обратное отображение, т.е. от суррогатной пары <H, L>
до Unicode кодовая точка C
, задается:
C = (H - 0xD800) * 0x400 + L - 0xDC00 + 0x10000
Ответ 2
Учитывая последовательность кодовых единиц UTF-16 (например, 16-разрядные номера, например, вы получаете от String.utf16
или просто массив чисел), вы можете использовать тип UTF16
и его метод decode
для превратите его в UnicodeScalars
, который затем можно преобразовать в String
.
Это немного шероховатый элемент, который принимает генератор (как он обрабатывает состояние) и возвращает перечисление, которое указывает результат (со связанным типом скаляра) или ошибку или завершение. Сравнение шаблонов Swift 2.0 делает его намного проще в использовании:
let u16data: [UInt16] = [0xD83D,0xDC36]
//or let u16data = "Hello, 🌍".utf16
var g = u16data.generate()
var s: String = ""
var utf16 = UTF16()
while case let .Result(scalar) = utf16.decode(&g) {
print(scalar, &s)
}
print(s) // prints 🐶