如何理解Unicode
- Unicode是個通用字符集,涵蓋了全世界所有字符
- 總范圍從
U+0000
~U+10FFFF
夕冲,十六進(jìn)制表示锨咙,共1114112
個字符眉踱,占用21位 - 通過每個字符挤忙,在Unicode字符集中有個一個碼點(diǎn)(code points)對應(yīng),如
U+F8FF
表示蘋果的icon - Unicode之規(guī)定了字符到碼點(diǎn)的對應(yīng)谈喳,但并沒有規(guī)定在機(jī)器中如何存儲册烈,即1個字節(jié)肯定無法存儲所有字符,如果有多個字節(jié)叁执,程序去讀這些字節(jié)時茄厘,遇到多個字節(jié)表示一個字符的情況矮冬,程序怎么知道要一次多去多個字節(jié)
- Unicode所有的字符被抽象成17個平面谈宛,每個平面包含了不同的字符Unicode表達(dá)
- 0號平面叫做BMP(Basic Multilingual Plane),基本多文種平面胎署,包括了常用的字符
- 為了兼容一些老的編碼系統(tǒng)吆录,有些字符看上去是一個,其實(shí)在Unicode中有多種表示形式
- 如
é
琼牧,既可以用U+00E9
表示恢筝,也可以用U+0065
(小寫字母e)加上U+0301
(尖括號)合成表示,這種叫做組合字符序列字符序列(ComposedString) - 上面
é
的例子巨坊,外觀一樣撬槽、含義也一樣的情況下,這兩個叫做標(biāo)準(zhǔn)等價
(canonically equivalent) - 有的情況趾撵,外觀一樣侄柔,但意義卻不同,比如小寫的拉丁連字符(
U+FB00
)兩個小寫拉丁字母ff
(U+0066 U+0066
)占调,外觀相同暂题,但卻含義不同。這種只能叫做相容等價
(compatibility equivalence)
- 如
UTF(Unicode Transformation Formats)
- Unicode轉(zhuǎn)換格式究珊,這是將Unicode真正用到程序中的一步薪者,即規(guī)定了在內(nèi)存、磁盤中如何存儲Unicode碼
- UTF-32剿涮,每個字符的Unicode碼點(diǎn)言津,都用32位來表示,由于32位>21位取试,所以程序自然知道如何讀取字符悬槽,但浪費(fèi)空間
- 這里的32位,或者后面的UTF-16的16位想括,稱作碼元(code unit)
- UTF-16陷谱,每個Unicode碼點(diǎn)用1-2個16位來表示,這時候就得規(guī)定讀取順序了,即字節(jié)順序標(biāo)記(BOM-Byte Order Mask)
- 所以烟逊,當(dāng)使用UTF-16編碼時渣窜,一定要標(biāo)示字節(jié)讀取順序,一般寫到文本開頭位置的兩個字節(jié)宪躯。默認(rèn)不寫的話是使用
高字節(jié)順序
- UTF-8
- 用1-4個字節(jié)標(biāo)示Unicode
- UTF-8和ASCII的所有碼點(diǎn)完全重合
- 不需要考慮字節(jié)讀取順序乔宿?UTF-8規(guī)定了字節(jié)讀取順序
NSString
-
iOS中表示Unicode中BMP的字符用
\uxxxx
,非BMP的要用\Uxxxxxxxx
表示NSString *s = @"\U0001F30D";//?? ```
C99不允許標(biāo)準(zhǔn)C字符集中的字符用
\uxxxx
這種形式表示访雪,所以在iOS中寫\u0041
(Unicode表示大寫字母A)是不允許蘋果文檔中說
NSString
將Unicode
表示為16位详瑞,這完全蘋果的錯誤睦刃,因?yàn)槲覀冎?code>Unicode是21位的裹芝,用16位怎么表示-
其實(shí)是
NSString
處理字符的任何方法都是以16位為基本處理單元- 那些少數(shù)的在Unicode中16位表示不過來的,在
NSString
中的length屬性就不是字符長度了
- 那些少數(shù)的在Unicode中16位表示不過來的,在
-
前文提到了組合字符序列征字,
NSString
也提供了組合與非組合之間的轉(zhuǎn)換方法精置,用于在標(biāo)準(zhǔn)等價
计寇、相容等價
幾種情況下進(jìn)行切換[test precomposedStringWithCanonicalMapping]; [test decomposedStringWithCanonicalMapping]; [test precomposedStringWithCompatibilityMapping]; [test decomposedStringWithCompatibilityMapping];
官方建議使用
NSString
時,將字符串看做子字符串的序列
脂倦,而不是字符的序列
番宁,因?yàn)樗淖址腿藗兛吹降恼J(rèn)為的字符不是一回事。但如果看做子字符串來處理赖阻,則其內(nèi)部的方法會很好的兼容各種問題NSString
中能夠保證返回正確字符數(shù)的方法是
NSString *s = @"The weather on \U0001F30D is \U0001F31E today.";
// The weather on ?? is ?? today.
NSRange fullRange = NSMakeRange(0, [s length]);
[s enumerateSubstringsInRange:fullRange
options:NSStringEnumerationByComposedCharacterSequences
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop)
{
NSLog(@"%@ %@", substring, NSStringFromRange(substringRange));
}];
Swift中的Unicode
- Swift中String對Unicode的支持蝶押,不像OC中的NString。String的
count
能夠很好的計(jì)算字符個數(shù)火欧,因?yàn)闀紤]到unicdoe各種組合的情況- 當(dāng)然也就可以把字符串當(dāng)做字符的序列了棋电,單個字符也可以正確地進(jìn)行處理了
- 正因?yàn)閺?fù)雜的Unicode各種情況,Swift中獲取子串或索引時布隔,就不能通過整型值來獲取了离陶。而是通過
String.Index
類型
- Swift中進(jìn)行字符或字符串等價判斷時,Swift認(rèn)為
標(biāo)準(zhǔn)等價
才是相等衅檀,相容等價
并不相等let latinCapitalLetterA: Character = "\u{41}"http://大寫拉丁字母A let cyrillicCapitalLetterA: Character = "\u{0410}"http://西里爾字母A print(latinCapitalLetterA + "-" + cyrillicCapitalLetterA) print(latinCapitalLetterA == cyrillicCapitalLetterA) //結(jié)果 A-A false