Swift 3.x 中 Strings/Characters 閑聊

unicode-latin-extended-additional.png

前言

本篇文章主要淺析字符串\字符在 Swift 和 Objective-C 之間的區(qū)別及其簡單用法维咸。如有不妥的地方還望大家及時幫忙糾正。

字符串判空

在 swift 語言中空字符串初始化方式常用的有兩種:

// 方式一:
let testEmptyString0 = ""

// 方式二:
let testEmptyString1 = String()

在開發(fā)過程中,我們應(yīng)該如何用正確的方式來對字符串進(jìn)行判空處理呢?


// 方式一:這種方式其實(shí)就是判斷 characters.count 是否為0
if testEmptyString0.isEmpty {
    // empty
}

// 方式二:
if testEmptyString0.characters.count {
    // empty
}

// 方式三:
if (testEmptyString0 as NSString).length {
    // empty
}

字符串長度計算

Objective-C

首先我們來回憶一下,在 Objective-C 中字符串是怎么計算長度的糕伐?我想大家都應(yīng)該知道砰琢。來看看蘋果是怎么說的:

A string object is implemented as an array of Unicode characters (in other words, a text string). An immutable string is a text string that is defined when it is created and subsequently cannot be changed. To create and manage an immutable string, use the NSString class. To construct and manage a string that can be changed after it has been created, use NSMutableString.

A string object presents itself as an array of Unicode characters. You can determine how many characters it contains with the length method and can retrieve a specific character with the characterAtIndex: method.

看完這段話蘸嘶,想必大家都明白 NSString 是怎么實(shí)現(xiàn)的,以及如何獲取其長度陪汽。通過 length 方法即可训唱,那么 length 方法是如何實(shí)現(xiàn)的呢?蘋果官方是這樣說的:length 方法利用的是 UTF-16 表示的十六位編碼單元數(shù)字為單位進(jìn)行計算的(The number of UTF-16 code units in the receiver.)挚冤。UTF-16是什么况增?(感興趣的童鞋可以看一下我之前寫的一篇文章,字符編碼(一))训挡,此處不再詳述澳骤。

Swift 3.0

Unicode 標(biāo)量表示

在 Swift 中,字符和字符串都是基于 Unicode 標(biāo)量建立的澜薄,采用21位二進(jìn)制進(jìn)行編碼为肮,共17個平面(除了基本多文種平面中的 UTF-16 代理對碼位外,即U+D800至U+DFFF的編碼空間)肤京,也就是說編碼范圍是U+0000-U+D7FFF 或者 U+E000-U+10FFFF颊艳。

A Unicode scalar is any Unicode code point in the range U+0000 to U+D7FF inclusive or U+E000 to U+10FFFF inclusive. Unicode scalars do not include the Unicode surrogate pair code points, which are the code points in the range U+D800 to U+DFFF inclusive.”

因此在 Swift 中,我們可直接采用 Unicode 標(biāo)量的形式來表示字符或字符串忘分,如:


let tingC = "\u{542C}" // 聽

let xinC = "\u{5FC3}" // 心
 

可擴(kuò)展的字形群集(簇)

在 Swift 中棋枕,每一個 Character 類型實(shí)例都代表單個可擴(kuò)展的字形群集——即由一個或多個 Unicode 標(biāo)量的序列組成的一個可讀字符。

漢字 “聽” 拼音為 tīng妒峦,以字母 ī 為例重斑,用兩種方式表示。第一種肯骇,可以直接用單個 Unicode 標(biāo)量 ī (LATIN SMALL LETTER I WITH MACRON) 來表示窥浪,即 U+012B卤恳,該字形群集中包含一個 Unicode 標(biāo)量。第二種寒矿,可以采用兩個 Unicode 標(biāo)量來表示突琳,一個拉丁字母 i (LATIN SMALL LETTER I) 加上一個音調(diào)符(元音,COMBINING MACRON ACCENT)的標(biāo)量符相,即 U+0069 U+0304拆融,這樣,當(dāng)字母 i 被 Unicode 文字渲染系統(tǒng)時就會轉(zhuǎn)換成 ī啊终,該字形群集中包含兩個 Unicode 標(biāo)量镜豹。


let tingO = "t" + "\u{0069}" + "ng" // Prints "ting "

let tingPS = "t" + "\u{0069}" + "\u{0304}" + "ng" // Prints "tīng"

let tingPD = "t" + "\u{012B}" + "ng" // Prints "tīng"

這兩種情況中,字母 ī 即代表了 Swift 中單個 Character 類型實(shí)例蓝牲,也代表了一個可擴(kuò)展的字形群集趟脂。想了解更多關(guān)于可擴(kuò)展的字形群集,可參考此鏈接例衍。

字符串長度

我們已經(jīng)簡單了解了可擴(kuò)展的字形群集昔期,現(xiàn)在我們再來看看 Swift 字符串中一些有意思的事。

Swift 中 String 類型佛玄,說白了就是 Character 類型實(shí)例的集合硼一,在開發(fā)過程中,我們一般采用兩種方式來求字符串的長度梦抢,第一種是轉(zhuǎn)成 Objective-C 中的 NSString 類型般贼,通過 length 方法來獲取其長度,第二種是通過字符串屬性 characters.count 的方式獲得奥吩。本小節(jié)主要討論第二種哼蛆,本文會在結(jié)尾針對這兩種方式進(jìn)行比較。

在 Swift 中霞赫,細(xì)心的同學(xué)或許已經(jīng)發(fā)現(xiàn) tingPD 與 tingPS 字符串的字符數(shù)量是一樣的:


print("tingPD-Count:\(tingPD.characters.count), tingPS-Count:\(tingPS.characters.count)") 
// Prints "tingPD-Count:4, tingPS-Count:4"

下面我們來解決此疑惑腮介,筆者已在前文說過,Swift 中 String\Character 都是基于 Unicode 標(biāo)量建立的绩脆,且 String 是 Character 的集合(即包含關(guān)系)萤厅,而 String 屬性 characters.count 其實(shí)就是計算 Character 的數(shù)量,那么 character 是怎么定義的呢靴迫,或者說什么才算是一個 character惕味?此時又引出了一個概念——字形群集界限(Grapheme Cluster Boundaries),而”什么才算是一個 character玉锌?“這個問題就是字形群集界限給出的答案名挥,想深入了解的同學(xué)請看:傳送門。從用戶感觀(user-perceived)角度講主守,不管是字符 ī(U+012B) 或者是 i(U+0069) 再加上一個音調(diào)符(U+0304)禀倔,這兩種表示最終的結(jié)果都是組成一個相同的可讀的字符榄融,因此 tingPD 與 tingPS 字符串中的字符數(shù)量是一樣的。

通過上文的簡單解釋救湖,可以得出兩個結(jié)論:

  1. 一個字符串拼接一個字符時愧杯,不一定會更改字符串的數(shù)量,即 characters.count 的值鞋既。

  2. 在沒有獲取到字形群集界限的時候力九,無法計算出該字符串的字符數(shù)量,因此必須遍歷字符串中全部的 Unicode 標(biāo)量以獲取字形群集界限邑闺,進(jìn)而確定字符串的字符數(shù)量跌前。

下面在看一個例子,相信大家都已明白輸出結(jié)果的原因:


var iWord = "i"

print("iword-Count: \(iWord.characters.count)")
// Prints "iword-Count: 1"

iWord += "\u{0304}" // ī
print("iword-Count: \(iWord.characters.count)")
// Prints "iword-Count: 1"

.length 與 .characters.count 的區(qū)別

首先 .length 是 Objective-C 中字符串長度計算方法陡舅,而 .characters.count 可以說是 Swift 中字符串長度計算方法抵乓,由于 Swift 中 String 類型可以轉(zhuǎn)成 Objective-C 中的 NSString 類型,因此在 Swift 開發(fā)過程中可能有如下兩種寫法:


print("tingPS.characters.count")
// Prints "4"
print("(tingPS as NSString).length")
// Prints "5"

從上述結(jié)果可看出靶衍,.length 方法得到的字符串長度為5灾炭,而 .characters.count 等于4,可能讀者會有點(diǎn)懵摊灭,同一個字符串怎么計算的長度不一致咆贬?其實(shí) .length 與 .characters.count 的計算原理在上文已經(jīng)做了解釋,本小節(jié)就簡單總結(jié)一下:

.length 與 .characters.count 返回值不總是相同的帚呼,.length 方法是采用 UTF-16 表示的編碼單元為單位進(jìn)行計算并返回的,即字母 i(U+0069) 皱蹦、音調(diào)符(U+0304)會當(dāng)做兩個字符煤杀,因而長度為2。.character.count 的值是通過字形群集界限來確定字符數(shù)量的沪哺,如還不理解請查看上文沈自。(PS:其實(shí)這里也是 Swift 中采用索引的方式訪問字符串的原因)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市辜妓,隨后出現(xiàn)的幾起案子枯途,更是在濱河造成了極大的恐慌,老刑警劉巖籍滴,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酪夷,死亡現(xiàn)場離奇詭異,居然都是意外死亡孽惰,警方通過查閱死者的電腦和手機(jī)晚岭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來勋功,“玉大人坦报,你說我怎么就攤上這事库说。” “怎么了片择?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵潜的,是天一觀的道長。 經(jīng)常有香客問我字管,道長夏块,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任纤掸,我火速辦了婚禮脐供,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘借跪。我一直安慰自己政己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布掏愁。 她就那樣靜靜地躺著歇由,像睡著了一般。 火紅的嫁衣襯著肌膚如雪果港。 梳的紋絲不亂的頭發(fā)上沦泌,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天,我揣著相機(jī)與錄音辛掠,去河邊找鬼谢谦。 笑死,一個胖子當(dāng)著我的面吹牛萝衩,可吹牛的內(nèi)容都是我干的回挽。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼猩谊,長吁一口氣:“原來是場噩夢啊……” “哼千劈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起牌捷,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤墙牌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后暗甥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喜滨,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年淋袖,在試婚紗的時候發(fā)現(xiàn)自己被綠了鸿市。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖焰情,靈堂內(nèi)的尸體忽然破棺而出陌凳,到底是詐尸還是另有隱情,我是刑警寧澤内舟,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布合敦,位于F島的核電站,受9級特大地震影響验游,放射性物質(zhì)發(fā)生泄漏充岛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一耕蝉、第九天 我趴在偏房一處隱蔽的房頂上張望崔梗。 院中可真熱鬧,春花似錦垒在、人聲如沸蒜魄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谈为。三九已至,卻和暖如春踢关,著一層夾襖步出監(jiān)牢的瞬間伞鲫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工签舞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留秕脓,地道東北人。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓瘪菌,卻偏偏與公主長得像撒会,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子师妙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容