天天看點

swift c語言 字元串的長度,《Advanced Swift》筆記:Swift字元串長度

var str = "Pokémon"

var nsstr = str as NSString

str.characters.count // 7

nsstr.length // 8

如上,同樣一個字元串,在String和NSString下,它的長度卻不一樣。因為Unicode編碼是一種可變長格式。Unicode字元串是由編碼點(code point)組成,而編碼點又是由編碼單元(code unit)組成。而在不同的編碼标準下,同一個字元串,可能會有不同的編碼方式。Swift中的String内心實作盡量符合“标準等價”的編碼規範,使我們更準确的處理字元長度。

在OC的NSString中,我們常用length方法來擷取字元串的長度,而在Swift的String中,沒有了length方法,我們通常是使用characters.count來擷取字元長度,如下:

var str = "Hello, playground"

var nsstr = str as NSString

str.characters.count // 17

nsstr.length // 17

以上兩種方法得出的字元串長度都是17,從代碼運作的結果看起來是很正确的,然而事實上真的如此嗎,我們再來看一組代碼:

var str = "Pokémon"

var nsstr = str as NSString

str.characters.count // 7

nsstr.length // 8

我們把字元串換成了Pokémon,結果nsstr.length方法計算出的字元串長度為8,而str.characters.count計算出來的是7,很明顯後者得出的長度是正确的。

那麼為什麼會出現何種情況呢,因為我們今天使用的字元串都是使用Unicode編碼的,它是一種可變長格式。Unicode字元串是由編碼點(code point)組成,而編碼點又是由編碼單元(code unit)組成。而在不同的編碼标準下,一個編碼點占用的編碼單元是不同的,比如對于UTF-32,一個編碼點會占用一個編碼單元,而對于UTF-8,一個編碼點則會占用一至四個編碼單元。

同一個字元串,可能會有不同的編碼生産方式,但不管采用何種編碼方式,同一個字元串最終應該是彼此相等,且含有相等字元數的,Unicode規範将此稱作“标準等價”(canonically equivalent)

比如字元é,我們可以通過單一的編碼u{00E9}來生成,也可以試用組合編碼的方式,即在字母e後面加上一個組合尖音符,u{0065}+u{0301},比如下面兩個字元串都是Pokémon,雖然它們采用不同的編碼方式,當它們的最終結果應該是等價的。

let single = "Pok\u{00E9}mon" // "Pokémon"

let double = "Pok\u{0065}\u{0301}mon" // "Pokémon"

single == double // true

single.characters.count // 7

double.characters.count // 7

Swift的字元串實作是在盡量符合Unicode這種标準等價規範。在Swift中,String不是一個集合,而是提供了多種方式來檢視字元串的類型,它可以編碼任意數量的編碼點,将他們合在一起可以組成單個字位簇(grapheme cluster)。

而NSString類型則不會考慮不同字元組合起來的等價性,它隻會按字面值進行計算和比較,是以将上面代碼的字元串換成NSString類型,結果就不一樣了:

let nssingle = single as NSString

let nsdouble = double as NSString

nssingle.length // 7

nsdouble.length // 8

nssingle == nsdouble // false

如果要對NSString的字元串進行準确的比較,應該使用compare方法。