讀懂Swift 2.0中字符串設(shè)計思路的改變
Swift提供了一種高性能的,兼容Unicode編碼的String實(shí)現(xiàn)作為標(biāo)準(zhǔn)庫的一部分。在Swift2中,String類型不再遵守CollectionType協(xié)議。在以前,String類型是字符的一個集合,類似于數(shù)組。現(xiàn)在,String類型通過一個characters屬性來提供一個字符的集合。
為什么會有這樣的變化呢?雖然模擬一個字符串作為字符的集合看起來非常自然,但是String類型與真正的集合類如Array、Set以及Dictionnary等類型表現(xiàn)得完全不同。這是一直都存在的,但是由于Swift2中增加了協(xié)議擴(kuò)展,這些不同就使得很有必要做些基本改變。
不同于部分的總和
當(dāng)你在集合中添加一個元素時,你希望集合中包含那個元素。也就是說,當(dāng)你給一個數(shù)組增加一個值,這個數(shù)組就包含了那個值。這同樣適用于Dictionary和Set。無論如何,當(dāng)你給字符串拼接一個組合標(biāo)記字符(combing mark character)時,字符串本身的內(nèi)容就改變了。
比如字符串cafe,它包含了四個字符:c,a,f ,e:
- var letters: [Character] = ["c", "a", "f", "e"]
- var string: String = String(letters)
- print(letters.count) // 4
- print(string) // cafe
- print(string.characters.count) // 4
如果你在字符串后面拼接了組合重音符號U+0301 ? ,字符串仍然有四個字符,但是***的字符現(xiàn)在是é:
- let acuteAccent: Character = "\u{0301}" // ′ COMBINING ACUTE ACCENT' (U+0301)
- string.append(acuteAccent)
- print(string.characters.count) // 4
- print(string.characters.last!) // é
字符串的characters屬性不包含原始的小寫字母 e,它也不包含剛剛拼接的重音符號?,字符串現(xiàn)在是一個帶著重音符號的小寫字母é:
- string.characters.contains("e") // false
- string.characters.contains("?") // false
- string.characters.contains("é") // true
如果你想要將字符串像其他集合類型那樣看待,這種結(jié)果很令人驚訝,就像你在一個集合中添加了UIColor.redColor()和UIColor.greenColor(),但是集合會報告它自己包含了一個UIColor.yellowColor()
通過字符內(nèi)容判斷
字符串與集合之間另一個不同是它們處理“相等”的方式。
-
只有在兩個數(shù)組的元素個數(shù)相同,并且在每一個對應(yīng)索引位置的元素也相等時兩個數(shù)組才是相等的。
-
只有在兩個集合的元素個數(shù)相同,并且***個集合中包含的元素,第二個集合也包括時兩個集合才相等。
-
兩個字典只有在有相同的鍵值對時才相等。
然而,String類型的相等建立在標(biāo)準(zhǔn)相等的基礎(chǔ)上。如果兩個字符串有相同的語義和外觀,即使它們實(shí)際上是用不同的Unicode碼構(gòu)成的,它們也是標(biāo)準(zhǔn)相等的。
考慮韓國的書寫系統(tǒng),包含了24個字母,或者叫Jamo,包含了單個的輔音和元音。當(dāng)寫出時這些字母就組成每個音節(jié)對應(yīng)的字符。例如,字符 ([ga])是由字母
([g])和
[a]構(gòu)成的。在Swift中,無論字符串是由分解的還是組合的字符構(gòu)成的,都被認(rèn)為是相等的。
這種行為再一次與Swift中的集合類型區(qū)別開來。這很令人驚訝就像是數(shù)組中的值
和 被認(rèn)為和 相等。
取決于你的視角
字符串不是集合。但是它們確實(shí)也提供了許多遵守CollectionType協(xié)議的views:
characters是Character類型值的集合,或者擴(kuò)展字形群集(extended grapheme clusters)
unicodeScalars是Unicode量值的集合(Unicode scalar values)
utf8是UTF-8編碼單元的集合(UTF-8)
utf16是UTF-16編碼單元的集合(UTF-16)
讓我們來看之前單詞 “café”的例子,由幾個單獨(dú)的字符[ c, a, f, e ] 和 [ ? ]構(gòu)成,下面是多種字符串的Views中所包含的內(nèi)容:
characters屬性將文字分段為擴(kuò)展字形群集,差不多接近用戶看到的字符(在這個例子中指c, a, f, 和 é)。由于字符串必須對整個字符串中的每一個位置(稱為碼位(code point))進(jìn)行迭代以確定字符的邊界,因此取得這個屬性的時間復(fù)雜度是線性的 O(n)。當(dāng)處理包含了人類可讀文本的字符串,以及上層的本地敏感的Unicode計算程序時,例如用到的localizedStandardCompare(_:)方法和localizedLowercaseString 屬性,都需要將字符逐字進(jìn)行處理。
unicodeScalars屬性提供了存儲在字符串中的量值,如果原始的字符串是通過字符é而不是e + ?創(chuàng)建的,這就會通過unicodeScalar屬性表示出來。當(dāng)你對數(shù)據(jù)進(jìn)行底層操作的時候使用這個API。
utf8和utf16屬性對應(yīng)地提供了它們所代表的代碼點(diǎn)(code points),這些值與字符串被轉(zhuǎn)化時寫入一個文件中的實(shí)際字節(jié)數(shù)是相一致的,并且來自一種特定的編碼方式。
UTF-8 編碼單元(code units)被許多 POSIX 的字符串處理 API 所使用,而 UTF-16 編碼單元(code units)則始終被用于表示 Cocoa 和 Cocoa Touch中的字符串長度和偏移量。
如果想了解更多 Swift 中關(guān)于字符和字符串的信息,請看The Swift Programming Language和 The Swift Standard Library Reference.