Unicode是一套国际通用的编码标准,用于在不同的系统中表示和处理文本数据。它让你可以用同一种形式表示几乎所有国家的所有语言,并且可对外部数据源进行读写操作,比如文本文件或者web页面。
Swift的String和Character类型是完全兼容Unicode的,之前文章中也提过。
Unicode标量
本质上,Swift中的String类型是通过Unicode标量创建的。一个Unicode标量是一个独一无二的21位的数字,代表了一个字符或者修饰符。比如U+0061表示了LATIN SMALL LETTER A的a,U+1F425表示FRONT-FACING BABY CHICK🐥。
需要注意的是不是所有的21位的Unicode编码单元都被分配给了一个字符,有一些是保留到未来分配的。已经被分配给字符使用的标量一般都有一个名字,比如上述例子中的LATIN SMALL LETTER A和FRONT-FACING BABY CHICK。
NOTE:一个Unicode标量是一个编码空间在[U+0000,U+D7FF] 或者[U+E000 ,U+10FFFF]中的任意编码单元。Unicode不包含代理对,也就是处于编码空间[U+D800, U+DFFF]中的编码单元。
可扩展的字形集群
Swift中的每一个Character实例都表示了一个单独的可扩展的字形集群。一个可扩展的字形集群由一个或者多个Unicode标量组成,并可以生成人类可读的字符。
let eAcute: Character = "\u{E9}" // é
let combinedEAcute: Character = "\u{65}\u{301}" // e followed by ́
// eAcute is é, combinedEAcute is é
上面是一个例子,字母é可以用单独的Unicode标量表示(LATIN SMALL LETTER E WITH ACUTE, or U+00E9),然而,字母é也可以用一对标量表示出来-----字母e(LATIN SMALL LETTER)后面跟随一个字母 ́(COMBINING ACUTE ACCENT) ,也就是U+0065跟随U+0301。在标量COMBINING ACUTE ACCENT被Unicode文本渲染系统渲染的时候,他会以图形化的方式作用于它前面的标量。把e变成é。
上面的两个例子中,字母é都是用一个单独的Character值来表示出字形集群。第一个例子,集群包含了一个标量,第二个例子,包含了2个标量。
可扩展的字符集群增加了灵活性,是我们可以使用一个单独的字符去表示很多复杂的脚本字符。比如,韩国字母中的音节可以表示成一组被预分解或者分解后的元素。下面两个字符在Swift中表示同一个字形:
let precomposed: Character = "\u{D55C}" // 한
let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
// precomposed is 한, decomposed is 한
可扩展的字符集群使可以包围其他的标量,使其称为字符的一部分:
let enclosedEAcute: Character = "\u{E9}\u{20DD}"
// enclosedEAcute is é⃝
地区指示符的Unicode标量可以被组合在一起,生成一个新的字符,比如把REGIONAL INDICATOR SYMBOL LETTER U (U+1F1FA)和 REGIONAL INDICATOR SYMBOL LETTER S (U+1F1F8)组合在一起:
let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
// regionalIndicatorForUS is 🇺🇸
字符的数量
要获取String中character的数量,可以使用String的count属性:
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
print("unusualMenagerie has \(unusualMenagerie.count) characters")
// 打印 "unusualMenagerie has 40 characters
值得注意的是,由于Swift中Character对可扩展自信集群的使用,使得字符串的连接或修改并不一定会改变字符串中字符的数量。
var word = "cafe"
print("the number of characters in \(word) is \(word.count)")
// "the number of characters in cafe is 4"
word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301
print("the number of characters in \(word) is \(word.count)")
// "the number of characters in café is 4
例如,你先使用4个字符cafe初始化了一个新的字符串,然后在末尾拼接上字符COMBINING ACUTE ACCENT (U+0301),结果还是4个字符,因为第4个字符从e变成了é。
NOTE:可扩展的字形群可以有多个Unicode标量组成,这就意味着不同的字符或者字符相同代表的结果却不同,需要存储的内存也不一样。因此,Swift中,字符串中的字符所占的内存不都是一样的。这就导致了如果不遍历字符串就无法确定字形群的边界,也就无法确定字符串中字符的数量。如果你正在处理特别长的字符串,注意count属性需要遍历整个字符串的Unicode标量以确定字符串的字符数量。
拥有相同字符的NSString的length和count返回的字符的数量不总是相同的。NSString的length是基于Utf-16的,也就是16位的代码单元,而不是String中可扩展字形群。
网友评论