Как я могу получить код кода Unicode символа?

Как я могу извлечь кодовую точку Unicode для данного Character без предварительного преобразования ее в String? Я знаю, что могу использовать следующее:

let ch: Character = "A"
let s = String(ch).unicodeScalars
s[s.startIndex].value // returns 65

но кажется, что должен быть более прямой способ выполнить это, используя стандартную библиотеку Swift. Раздел "Руководство по языку" "Работа с символами" и "Unicode" обсуждать только итерации по символам в String, не работая напрямую с Character s.

Ответ 1

Из того, что я могу собрать в документации, они хотят, чтобы вы получили значения Character от String, потому что это дает контекст. Является ли этот Character закодированным с UTF8, UTF16 или 21-битными кодовыми точками (скалярами)?

Если вы посмотрите на то, как Character определен в структуре Swift, это фактически значение enum. Это, вероятно, сделано из-за различных представлений от String.utf8, String.utf16 и String.unicodeScalars.

Кажется, они не ожидают, что вы будете работать со значениями Character, а скорее Strings, а вы, как программист, решаете, как их получить из самого String, позволяя сохранить кодировку.

Тем не менее, если вам нужно получить кодовые точки в сжатой форме, я бы рекомендовал расширение, подобное такому:

extension Character
{
    func unicodeScalarCodePoint() -> UInt32
    {
        let characterString = String(self)
        let scalars = characterString.unicodeScalars

        return scalars[scalars.startIndex].value
    }
}

Затем вы можете использовать его так:

let char : Character = "A"
char.unicodeScalarCodePoint()

Таким образом, кодировка строк и символов является сложной задачей, когда вы учитываете все возможности. Чтобы позволить каждой возможности быть представленными, они пошли с этой схемой.

Также помните, что это версия 1.0, я уверен, что они скоро расширят синтаксический сахар Swift.

Ответ 2

Я думаю, что есть некоторые недоразумения в отношении Unicode. Сам Unicode является НЕ кодировкой, не не преобразовывает кластеры графемы (или "символы" из уважения к чтению) в любую двоичную последовательность. Unicode - это просто большая таблица, которая собирает все кластеры графемы, используемые всеми языками на Земле (неофициально также включает в себя клингон). Эти кластеры grapheme организованы и индексируются кодовыми точками (21-битное число в swift и выглядит как U + D800). Вы можете найти, где персонаж, которого вы ищете в большой таблице Юникода, с помощью кодовых точек

Между тем, протокол UTF8, UTF16, UTF32 фактически кодирует. Да, существует несколько способов кодирования символов Юникода в двоичные последовательности. Использование протокола зависит от проекта, который вы работаете, но большая часть веб-страницы кодируется UTF-8 (вы можете проверить ее сейчас).

Концепция 1: Точка Unicode называется Unicode Scalar в Swift

Сканер Unicode представляет собой любую кодовую точку Unicode в диапазоне U + 0000 до U + D7FF включительно или U + E000 до U + 10FFFF включительно. Сканеры Unicode не включают в себя кодовые точки суррогатной пары Unicode, которые являются кодовыми точками в диапазоне U + D800 до U + DFFF включительно.

Концепция 2: Элемент Code - это абстрактное представление кодировки.

Рассмотрим следующий фрагмент кода

let theCat = "Cat!🐱"

for char in theCat.utf8 {
    print("\(char) ", terminator: "") //Code Unit of each grapheme cluster for the UFT8 encoding
}
print("")
for char in theCat.utf8 {
    print("\(String(char, radix: 2)) ", terminator: "") //Encoding of each grapheme cluster for the UTF8 encoding
}
print("")


for char in theCat.utf16 {
    print("\(char) ", terminator: "") //Code Unit of each grapheme cluster for the UFT-16 encoding
}
print("")
for char in theCat.utf16 {
    print("\(String(char, radix: 2)) ", terminator: "") //Encoding of each grapheme cluster for the UTF-16 encoding
}
print("")

for char in theCat.unicodeScalars {
    print("\(char.value) ", terminator: "") //Code Unit of each grapheme cluster for the UFT-32 encoding
}
print("")
for char in theCat.unicodeScalars {
    print("\(String(char.value, radix: 2)) ", terminator: "") //Encoding of each grapheme cluster for the UTF-32 encoding
}

Абстрактное представление означает: блок кода записывается номером base-10 (десятичное число), равным кодировке base-2 (двоичная последовательность). Кодирование сделано для машин, Code Unit больше подходит для людей, его легко читать, чем двоичные последовательности.

Концепция 3: У символа могут быть разные юникодные точки. Это зависит от того, как персонаж заключен в какие кластеры графема (вот почему я сказал "Персонажи" от уважения к чтению людей в начале)

рассмотрим следующий фрагмент кода

let precomposed: String = "\u{D55C}"
let decomposed: String = "\u{1112}\u{1161}\u{11AB}" 
print(precomposed.characters.count) // print "1"
print(decomposed.characters.count) // print "1" => Character != grapheme cluster
print(precomposed) //print "한"
print(decomposed) //print "한"

Символы precomposed и decomposed визуально и лингвистически равны. Но они имеют разную точку Unicode и другой код, если они закодированы одним и тем же протоколом кодирования (см. следующий пример)

for preCha in precomposed.utf16 {
    print("\(preCha) ", terminator: "") //print 55357 56374 128054 54620
}

print("")

for deCha in decomposed.utf16 {
    print("\(deCha) ", terminator: "") //print 4370 4449 4523
}

Дополнительный пример

var word = "cafe"
print("the number of characters in \(word) is \(word.characters.count)")

word += "\u{301}"

print("the number of characters in \(word) is \(word.characters.count)")

Резюме: Кодовые точки, как индекс позиции символов в Юникоде, не имеет ничего общего с схемами кодирования UTF-8, UTF-16 и UTF-32.

Дополнительные чтения:

http://www.joelonsoftware.com/articles/Unicode.html

http://kunststube.net/encoding/

https://www.mikeash.com/pyblog/friday-qa-2015-11-06-why-is-swifts-string-api-so-hard.html

Ответ 3

Я согласен с вами, должен быть способ получить код непосредственно от персонажа. Но все, что я могу предложить, это сокращение:

let ch: Character = "A"
for code in String(ch).utf8 { println(code) }

Ответ 4

Я думаю, проблема в том, что Character не представляет собой кодовую точку Unicode. Он представляет собой "Unicode grapheme cluster", который может состоять из нескольких кодовых точек.

Вместо этого UnicodeScalar представляет собой кодовую точку Unicode.

Ответ 5

Вы пробовали:

import Foundation

let characterString: String = "abc"
var numbers: [Int] = Array<Int>()
for character in characterString.utf8 {
    let stringSegment: String = "\(character)"
    let anInt: Int = stringSegment.toInt()!
    numbers.append(anInt)
}

numbers

Вывод:

[97, 98, 99]

Он также может быть только одним символом в строке.