Swift 中的字符串截取
發(fā)表于2016-12-14||100
Substring in Swift 3.0
Info:
macOS 10.12.2 Beta
Xcode 8.2 Beta
Swift 3.0
最近更文的頻率也是越來(lái)越慢,除去已到期末的緣故,加上在忙老師的項(xiàng)目,自己的時(shí)間便被壓縮殆盡。不過(guò)好在Swift 設(shè)計(jì)模式基本上已經(jīng)更新完畢,下來(lái)就準(zhǔn)備補(bǔ)齊每個(gè)模式對(duì)應(yīng)的說(shuō)明。
在嘗試使用 Swift 實(shí)現(xiàn)《大話(huà)設(shè)計(jì)模式》一書(shū)中的解釋器模式時(shí),書(shū)中的 Demo 多次使用了截取字符串的方法,當(dāng)然,Swift 作為一門(mén)先進(jìn)的編程語(yǔ)言不會(huì)缺少這一常用的方法。然而在使用中,可能由于 Swift 是一門(mén)較為注重(類(lèi)型)安全的語(yǔ)言,其字符串截取方法使用方式與 Java 等編程語(yǔ)言便有一些語(yǔ)法上的不同。在 Swift 自身的迭代過(guò)程中,這部分的語(yǔ)法變化也很大。所以這次就來(lái)簡(jiǎn)單研究一下 Swift 中的字符串截取。需要注意的是,雖然 Swift 也可以使用 NSString 類(lèi)型的字符串,而且兩者可以很容易的橋接,但考慮到個(gè)人對(duì) Objective-C 的了解程度,便暫時(shí)不探討。
索引與下標(biāo),即 index 和 subscript。一般來(lái)說(shuō),兩者的概念是類(lèi)似的,不過(guò)個(gè)人覺(jué)得索引有泛指的概念,而下標(biāo)是具體的。
Swift 中字符串的索引類(lèi)型并不是其他語(yǔ)言中的整型(int),而是 String.Index。String.Index,即標(biāo)注字符串的索引類(lèi)型。在 Swift 的標(biāo)準(zhǔn)庫(kù)中,可以看到其本質(zhì)是String.CharacterView.Index的別名。
/// The index type for subscripting a string.
publictypealiasIndex=String.CharacterView.Index
再進(jìn)一步查看String.CharacterView,即創(chuàng)建給定字符串的字符視圖類(lèi)型。
publicstructCharacterView{
/// Creates a view of the given string.
publicinit(_text:String)
}
常用的"maimieng.com".characters的類(lèi)型其實(shí)就是String.CharacterView類(lèi)型。.characters將字符串內(nèi)容轉(zhuǎn)化為字符序列的視圖。
字符串必然是一個(gè)字符的有限序列,Swift 為了方便開(kāi)發(fā)者迅速定位,便集成了startIndex和endIndex。但是需要注意的是:startIndex是指字符串的第一個(gè)字符的下標(biāo),而endIndex是指字符串的最后一個(gè)字符之后的下標(biāo)。當(dāng)字符串為空時(shí),startIndex和endIndex相同。
varstr ="maimieng.com"
print(str.characters.count)
print(str.startIndex)
print(str.endIndex)
// 12
// Index(_base: Swift.String.UnicodeScalarView.Index(_position: 0), _countUTF16: 1)
// Index(_base: Swift.String.UnicodeScalarView.Index(_position: 12), _countUTF16: 0)
從上面的 Demo 也可以看出,startIndex的位置為 0,而endIndex的位置為 12,等同于字符串的長(zhǎng)度,而不是字符串長(zhǎng)度減一。
除了給出了起始和結(jié)尾的下標(biāo),Swift 也提供了根據(jù)下標(biāo)定位其他索引的方法:
publicfuncindex(after i: String.Index)->String.Index
publicfuncindex(before i: String.Index)->String.Index
publicfuncindex(_i: String.Index, offsetBy n: String.IndexDistance)->String.Index
publicfuncindex(_i: String.Index, offsetBy n: String.IndexDistance, limitedBy limit: String.Index)->String.Index?
這樣就可以通過(guò)給出的startIndex和endIndex來(lái)定位到其他的下標(biāo)了。
varstr ="maimieng.com"
// 返回傳入下標(biāo)之后的下標(biāo)
print(str.index(after: str.startIndex))
// 返回傳入下標(biāo)之前的下標(biāo)
print(str.index(before: str.endIndex))
// 返回傳入下標(biāo)偏移后的下標(biāo)(偏移量可正可負(fù)可為 0)
print(str.index(str.startIndex, offsetBy:1))
// print(str.index(str.endIndex, offsetBy: 10))
// 作用同上,但如果超過(guò)傳入的界限返回 nil
print(str.index(str.endIndex, offsetBy:10, limitedBy: str.endIndex) ??"越界")
下標(biāo)之間的間距,也可以利用func distance(from start: String.Index, to end: String.Index) -> String.IndexDistance方法求出:
varstr ="maimieng.com"
print(str.distance(from: str.startIndex, to: str.endIndex))
// 12
print(str.distance(from: str.endIndex, to: str.startIndex))
// -12
Range 即范圍,Swift 中實(shí)現(xiàn)了 Comparable 協(xié)議的類(lèi)型都可以用 Range 來(lái)表示范圍。以下的 Range 特指:Range。
Range 的構(gòu)造方法是init(uncheckedBounds bounds: (lower: Bound, upper: Bound))。即傳入一個(gè)元組,返回一個(gè)范圍。需要注意的是:這個(gè)范圍 Swift 是不會(huì)檢查的,需要程序員自覺(jué)維護(hù)。
varstr ="maimieng.com"
// 前閉后開(kāi)
letrangeA =Range(uncheckedBounds: (str.startIndex, str.endIndex))
print(rangeA)
// Index(_base: Swift.String.UnicodeScalarView.Index(_position: 0), _countUTF16: 1)..
print(str.substring(with: rangeA))
// maimieng.com
// 即使范圍首尾顛倒,也沒(méi)有報(bào)錯(cuò)
letrangeB =Range(uncheckedBounds: (str.endIndex, str.startIndex))
print(rangeB)
// Index(_base: Swift.String.UnicodeScalarView.Index(_position: 12), _countUTF16: 0)..
// 但在使用中會(huì)出錯(cuò)
// fatal error: Can't form Range with upperBound < lowerBound
// str.substring(with: rangeB)
在上面的 Demo 中,從輸出中也可以看出,init(uncheckedBounds bounds: (lower: Bound, upper: Bound))構(gòu)造的范圍是一個(gè)前閉后開(kāi)的區(qū)間。
Swift 中,字符串本身也能構(gòu)造出 Range,例如:得到字符串子串的范圍,若不存在則返回 nil:
varstr ="maimieng.com"
// 返回前閉后開(kāi)的范圍
print(str.range(of:".com") ??"不存在")
// Index(_base: Swift.String.UnicodeScalarView.Index(_position: 8), _countUTF16: 1)..
在 Range 一節(jié)的 Demo 中,已經(jīng)使用了substring(with:)方法測(cè)試范圍的使用。Swift 中的字符串截取與其他語(yǔ)言其實(shí)是相似的,都是根據(jù)索引或索引范圍來(lái)截取,只是 Swift 中的索引的類(lèi)型不是整型,稍有麻煩。
varstr ="maimieng.com"
// 截取傳入范圍(左開(kāi)右閉)的子串
letrange =Range(uncheckedBounds: (str.startIndex, str.endIndex))
print(str.substring(with: range))
// 從傳入的索引開(kāi)始截取到末尾(含 str.startIndex 元素)
print(str.substring(from: str.startIndex))
// 從傳入的索引的前一個(gè)位置開(kāi)始截取到頭部(不含 str.endIndex 元素)
print(str.substring(to: str.endIndex))
// maimieng.com
// maimieng.com
// maimieng.com
以上的 Demo 便是 Swift 中最基本的截取字符串使用。然而有時(shí)候條件一多,代碼的重復(fù)率也會(huì)增加,那么可以利用 Swift 中的
extension 來(lái)擴(kuò)展原有的 String,讓 Swift 的 String 可以像 C#、Java 一樣截取字符串,需要注意的是 這里的
IndexDistance 實(shí)際上是 String.CharacterView.IndexDistance 的別名,而
String.CharacterView.IndexDistance 又是 Int 類(lèi)型的別名。
extensionString{
funcsubstring(from: IndexDistance)->String? {
letindex =self.index(self.startIndex, offsetBy: from)
returnstr.substring(from: index)
}
funcsubstring(to: IndexDistance)->String? {
letindex =self.index(self.startIndex, offsetBy: to +1)
returnstr.substring(to: index)
}
funcsubstring(with range: Range)->String? {
letlower =self.index(self.startIndex, offsetBy: range.lowerBound)
letupper =self.index(self.startIndex, offsetBy: range.upperBound)
letrange =Range(uncheckedBounds: (lower, upper))
returnstr.substring(with: range)
}
funcsubstring(_lower: IndexDistance,_range: IndexDistance)->String? {
letlowerIndex =self.index(self.startIndex, offsetBy: lower)
letupperIndex =self.index(lowerIndex, offsetBy: range)
letrange =Range(uncheckedBounds: (lowerIndex, upperIndex))
returnstr.substring(with: range)
}
}
print(str.substring(to:0) ??"nil")
print(str.substring(from:2) ??"nil")
print(str.substring(with:0..<1) ??"nil")
print(str.substring(1,2) ??"nil")
// m
// imieng.com
// m
// ai
Documentation & API Reference
原文出處:https://maimieng.com/2016/37/