Swift 4 String

Swift的字符串和OC有很大差別匪燕,下面詳細(xì)學(xué)習(xí)下留荔。

Grapheme Clusters (字形簇)

As you know, a string is made up of a collection of Unicode characters. Until now, you have considered one code point to precisely equal one character, and vice versa. However the term "character" is fairly loose.

就我們目前所知道的,字符串是由一連串的Unicode字符組成泻云。于此同時(shí)滓彰,我們也是通過一個(gè)代碼點(diǎn)來直接判斷兩個(gè)字符是否相等,反之亦然鸥印。但是勋功,"character"其實(shí)概念是相當(dāng)松散的坦报。

直入主題,在swift中我們表示cafe可以有兩種方式:
“ One example is the é in café, 其中é用unicode編碼單獨(dú)表示是233狂鞋,如果用combining character的形式就是e+聲調(diào)的形式片择,e是101,聲調(diào)是769骚揍,而后者這種方式就是Unicode標(biāo)準(zhǔn)中的字形簇字管。在swift中字形簇用Character來表示。

可能上面的解釋還不夠清楚解釋字形簇在swift的中意義信不,下面看個(gè)例子:

let cafeNormal = "café"
let cafeCombining = "cafe\u{0301}"

cafeNormal.count     // 4
cafeCombining.count  // 4

\u表示的是Unicode的速記法書寫形式嘲叔,我們可以用Unicode速記法書寫任意形式的Unicode編碼。這里為啥不直接寫呢抽活,因?yàn)殒I盤上敲不出來e加聲調(diào)的字符硫戈。

可以看到代碼二者的輸出長度一致,為什么呢下硕?因?yàn)樵赟wift中丁逝,string是被看做字形簇的一個(gè)集合汁胆,e加聲調(diào)就是一個(gè)字形簇,所以這里長度輸出都是4霜幼。

上面的結(jié)果意味著我們要花費(fèi)一個(gè)線性的時(shí)間去找出字符串的長度嫩码,因?yàn)槲覀円饌€(gè)遍歷字符串去找出有多少個(gè)字形簇。所以罪既,我們不能簡單的通過內(nèi)存中長度來判斷這個(gè)字符串有多大铸题。

挺麻煩的吧,所以最后swift給我們提供了unicodeScalars這種方式來訪問string的底層Unicode數(shù)據(jù):

cafeNormal.unicodeScalars.count     // 4
cafeCombining.unicodeScalars.count  // 5
for codePoint in cafeCombining.unicodeScalars {
  print(codePoint.value)
}

輸出結(jié)果:

99
97
102
101
769

Indexing strings(字符串索引)

在Swift中琢感,我們無法通過下標(biāo)來直接訪問字符串的具體字符回挽,為啥呢?因?yàn)镾wift需要我們關(guān)注下string的底層原理猩谊,原理是啥千劈?就是我們上面說的字形簇。所以牌捷,字符串索引訪問的方式就比較蛋疼了墙牌,我們只能夠使用特殊的字符串索引類型而不是整形的下標(biāo)類型來訪問。

let firstIndex = cafeCombining.startIndex

這里firstIndex的數(shù)據(jù)類型就是String.Index類型暗甥。這里我們只是拿到了索引喜滨,具體訪問:

let firstChar = cafeCombining[firstIndex]

firstChar結(jié)果就是c。

下面撤防,我們嘗試訪問結(jié)尾的字符:

let lastIndex = cafeCombining.endIndex
let lastChar = cafeCombining[lastIndex]

但是虽风,錯(cuò)誤出現(xiàn)了

fatal error: Can't form a Character from an empty String

為啥呢?原因就是終結(jié)索引實(shí)際上是在字符串結(jié)尾的1寄月,(let cafeCombining = "cafe\u{0301}")辜膝。所以,我們需要這么做:

let lastIndex = cafeCombining.index(before: cafeCombining.endIndex)
let lastChar = cafeCombining[lastIndex]

也可以這么做:

let fourthIndex = cafeCombining.index(cafeCombining.startIndex, offsetBy: 3)
let fourthChar = cafeCombining[fourthIndex]

Equality with combining characters (如何判斷組合字符是否相等)

Swift采用一種叫canonicalization(規(guī)范化)的技術(shù)來處理象形字符之間的比較漾肮,和傳統(tǒng)的其他語言逐個(gè)字符比較厂抖,然后判斷是否都相等不同。Swift首先對字符串進(jìn)行規(guī)范化操作克懊,讓2個(gè)字符串變成同一種風(fēng)格忱辅,然后再逐個(gè)進(jìn)行比較,具體的實(shí)現(xiàn)方式我們不必關(guān)注谭溉,了解這個(gè)特性即可墙懂。

let equal = cafeNormal == cafeCombining

在Swift中,上面代碼的執(zhí)行結(jié)構(gòu)是true.

Strings as bi-directional collections(字符串作為雙向集合)

Swift做了一些內(nèi)存優(yōu)化扮念,雙向集合就是一種损搬,其實(shí)概念很簡單,看下代碼就知道了。

let name = "Matt"
let backwardsName = name.reversed()

backwardsName的類型是string嗎场躯?不是谈为,其實(shí)在swift中它是 reversed collection 類型,Swift做了內(nèi)存優(yōu)化踢关,他還是指向源字符串的內(nèi)存空間伞鲫。但是,使用起來和其他字符串并無差別签舞。

let secondCharIndex = backwardsName.index(backwardsName.startIndex, offsetBy: 1)
let secondChar = backwardsName[secondCharIndex] // "t”

如果你確實(shí)想要開辟一塊新空間秕脓,那么這么做:

let backwardsNameString = String(backwardsName)

Substrings (子串)

首先,我們來看一段代碼:

let fullName = "Matt Galloway"
let spaceIndex = fullName.index(of: " ")!
let firstName = fullName[fullName.startIndex..<spaceIndex] // "Matt”
  • open-ended range (開放范圍)
    Swift提供了一種新的范圍類型:開放范圍儒搭。我們只需要提供一個(gè)索引位置吠架,而另一個(gè)索引則被默認(rèn)假設(shè)為集合的開始或結(jié)尾,類似于數(shù)學(xué)中的開閉區(qū)間搂鲫。

應(yīng)用這個(gè)類型傍药,我們可以將上面的代碼修改如下:

let firstName = fullName[..<spaceIndex]
let lastName = fullName[fullName.index(after: spaceIndex)...]

細(xì)心點(diǎn),我們可以發(fā)現(xiàn)這時(shí)firstName的數(shù)據(jù)類型是Substring而不是string類型魂仍,這里其實(shí)和reversed string是一個(gè)原理拐辽,Swift本身是做了內(nèi)存優(yōu)化的,如果你想要一個(gè)全新string那么就這么做:

let lastNameString = String(lastName)

看到這里擦酌,我們不禁會想俱诸,為什么Swift的設(shè)計(jì)者要以這么復(fù)雜的方式來處理字符串呢?其實(shí)Substring在swift中是一個(gè)很巧妙的設(shè)計(jì)赊舶。Substring分享父string的內(nèi)存睁搭,這就意味著我們處理一個(gè)子串時(shí)不需要額外的內(nèi)存開銷。然后笼平,當(dāng)我們確實(shí)需要一個(gè)string類型的字符串時(shí)园骆,我們可以顯示的創(chuàng)建一個(gè)新的字符串類型,然后內(nèi)存中的數(shù)據(jù)就會拷貝到這個(gè)新字符串當(dāng)中出吹。
Swift的設(shè)計(jì)者本可以默認(rèn)的讓這種拷貝行為執(zhí)行遇伞,但是沒有這么做辙喂,設(shè)計(jì)者就是想讓你持有substring的類型捶牢,然后明確的讓你明白這底層到底發(fā)生了什么。如果你不是在函數(shù)返回值或者函數(shù)傳參的時(shí)候明確的遇到了要求數(shù)據(jù)類型為string時(shí)巍耗,你可能都不知道你持有的一直是substring類型的字符串秋麸,這時(shí),我們就可以用substring類型的字符串來顯示的初始化一個(gè)string類型的新字符串炬太。
Swift的設(shè)計(jì)者就是這么固執(zhí)灸蟆,但是,設(shè)計(jì)者這么嚴(yán)謹(jǐn)?shù)氖褂米址褪歉嬖V我們亲族,字符串使用很頻繁炒考,而且處理起來很復(fù)雜可缚,這點(diǎn)在日后編碼中是很重要的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末斋枢,一起剝皮案震驚了整個(gè)濱河市帘靡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瓤帚,老刑警劉巖描姚,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異戈次,居然都是意外死亡轩勘,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門怯邪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绊寻,“玉大人,你說我怎么就攤上這事悬秉¢凰梗” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵搂捧,是天一觀的道長驮俗。 經(jīng)常有香客問我,道長允跑,這世上最難降的妖魔是什么王凑? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮聋丝,結(jié)果婚禮上索烹,老公的妹妹穿的比我還像新娘。我一直安慰自己弱睦,他們只是感情好百姓,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著况木,像睡著了一般垒拢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上火惊,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天求类,我揣著相機(jī)與錄音,去河邊找鬼屹耐。 笑死尸疆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播寿弱,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼犯眠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了症革?” 一聲冷哼從身側(cè)響起阔逼,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎地沮,沒想到半個(gè)月后嗜浮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摩疑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年危融,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雷袋。...
    茶點(diǎn)故事閱讀 40,115評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吉殃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出楷怒,到底是詐尸還是另有隱情蛋勺,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布鸠删,位于F島的核電站抱完,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏刃泡。R本人自食惡果不足惜巧娱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望烘贴。 院中可真熱鬧禁添,春花似錦、人聲如沸桨踪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锻离。三九已至铺峭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間纳账,已是汗流浹背逛薇。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留疏虫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像卧秘,于是被迫代替她去往敵國和親呢袱。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評論 2 355

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

  • String在Swift 4 的新特性深受大眾喜愛(至少我是很喜歡的).String API 在Swift 4 中...
    Lucky閃閃星閱讀 748評論 0 1
  • 刪掉重新來一次吧翅敌,記得改那個(gè)腳本修改 /home/ubuntu/eos/scripts/install_depen...
    盧衍泓閱讀 1,144評論 0 1
  • 沖動之下羞福,成功加到微信,“厄卿蹋”的一聲治专,手機(jī)鈴聲表對方已通過你的驗(yàn)證要求,誰也沒有先說話遭顶,哼张峰,就看誰先忍不住。
    愛天藍(lán)QG閱讀 140評論 1 0
  • 喜歡在路上 欣賞一閃而過風(fēng)景 特別是行走在深谷大橋上 腳下溝壑縱橫 遠(yuǎn)處山嵐霧靄 晴天洋溢著活潑 雨天訴說著多情 ...
    凡木有心閱讀 187評論 0 0
  • 逢人便說:“我微信紅包被人偷了278元棒旗,我卡里面的錢會不會也會被偷走喘批。”結(jié)果有人說:“微信和卡不一樣铣揉∪纳睿”但是我還是...
    田萍閱讀 151評論 0 2