如何获取角色的Unicode代码点?

时间:2014-06-08 00:56:18

标签: unicode swift

如何在不首先将其转换为Character的情况下提取给定String的Unicode代码点?我知道我可以使用以下内容:

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

但似乎应该有一个更直接的方法来使用Swift的标准库来实现这一点。语言指南部分"Working with Characters""Unicode"仅讨论迭代String中的字符,而不是直接使用Character s。

6 个答案:

答案 0 :(得分:31)

根据我在文档中收集的内容,他们希望您从Character获取String值,因为它提供了上下文。这个Character是用UTF8,UTF16还是21位代码点(标量)编码的?

如果你看看如何在Swift框架中定义Character,它实际上是enum值。这可能是由于String.utf8String.utf16String.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的语法糖。

答案 1 :(得分:17)

我认为对Unicode存在一些误解。 Unicode本身是 NOT 编码,将任何字形集群(或人类阅读方面的“字符”)转换为任何类型的二进制序列。 Unicode只是一个大表,它收集地球上所有语言使用的所有字形簇(非正式地还包括克林贡语)。这些字形簇由代码点组织和索引(swift中的21位数字,看起来像U + D800)。您可以使用代码点

在大型Unicode表中找到您要查找的字符的位置

同时,名为UTF8,UTF16,UTF32的协议实际上是编码。是的,有多种方法可以将Unicode字符编码为二进制序列。使用哪种协议取决于您正在使用的项目,但大多数网页都是由UTF-8编码的(您现在可以实际检查它)。

概念1:在Swift中将Unicode点称为 Unicode标量

  

Unicode标量是U + 0000到U + D7FF(含)或U + E000到U + 10FFFF(含)的任何Unicode代码点。 Unicode标量不包括Unicode代理对代码点,这些代码点是U + D800到U + DFFF范围内的代码点。

概念2: 代码单元是编码的抽象表示。

请考虑以下代码段

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
}

抽象表示意味着:代码单元由基数为10的数字(十进制数)写入,它等于基数为2的编码(二进制序列)。对机器进行编码,代码单元更适合人类,它比二进制序列更容易阅读。

概念3:字符可能具有不同的Unicode点。这取决于角色如何通过什么字形聚类来缩小(这就是为什么我在开始时从人类阅读方面说“人物”

请考虑以下代码段

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 "한"

字符precomposeddecomposed在视觉上和语言上相同,但如果它们使用相同的编码协议编码,则它们具有不同的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)")

摘要代码点,Aka是Unicode中字符的位置索引,与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

答案 2 :(得分:6)

我认为问题是Character不代表Unicode代码点。它代表一个“Unicode字形集群”,它可以包含多个代码点。

相反,UnicodeScalar表示Unicode代码点。

答案 3 :(得分:6)

我同意你的观点,应该有一种直接从角色获取代码的方法。但我能提供的只是一个简写:

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

答案 4 :(得分:0)

你试过了吗?

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]

字符串中也可能只有一个字符。

答案 5 :(得分:0)

#1。使用Unicode.Scalar的{​​{1}}属性

在Swift 5中,value具有一个value属性,该属性具有以下声明:

  

Unicode标量的数字表示形式。

Unicode.Scalar

下面的Playground示例代码演示如何遍历var value: UInt32 { get } 的{​​{1}}属性并打印组成它的每个Unicode标量的值:

unicodeScalars

或者,如果您只想打印Character的第一个unicode标量的值,则可以使用下面的示例代码:

let character: Character = "A"
for scalar in character.unicodeScalars {
    print(scalar.value)
}

/*
 prints: 65
 */

#2。使用Character的{​​{1}}属性

如果您真正想要的是获取字符的ASCII编码值,则可以使用let character: Character = "A" let scalars = character.unicodeScalars let firstScalar = scalars[scalars.startIndex] print(firstScalar.value) /* prints: 65 */ 的{​​{3}}。 Character具有以下声明:

  

如果是ASCII,则返回此字符的ASCII编码值。

asciiValue

下面的Playground示例代码显示了如何使用Character

asciiValue
var asciiValue: UInt8? { get }