你如何使用String.substringWithRange? (或者,Ranges如何在Swift中工作?)

我还没有弄清楚如何在Swift中获得一个string的子String

 var str = “Hello, playground” func test(str: String) -> String { return str.substringWithRange( /* What goes here? */ ) } test (str) 

我无法在Swift中创build一个Range。 在游乐场自动完成并不是非常有帮助 – 这就是它所暗示的:

 return str.substringWithRange(aRange: Range<String.Index>) 

我还没有find任何有用的Swift标准参考库。 这是另一个疯狂的猜测:

 return str.substringWithRange(Range(0, 1)) 

和这个:

 let r:Range<String.Index> = Range<String.Index>(start: 0, end: 2) return str.substringWithRange(r) 

我见过其他答案( 在Swiftstring中查找字符索引 )似乎表明,由于StringNSString的桥接types,“旧”方法应该工作,但不清楚如何 – 例如,这不工作(看起来不是有效的语法):

 let x = str.substringWithRange(NSMakeRange(0, 3)) 

思考?

你可以使用substringWithRange方法。 它需要一个开始和结束String.Index。

 var str = "Hello, playground" str.substringWithRange(Range<String.Index>(start: str.startIndex, end: str.endIndex)) //"Hello, playground" 

要更改开始和结束索引,请使用advancedBy(n)。

 var str = "Hello, playground" str.substringWithRange(Range<String.Index>(start: str.startIndex.advancedBy(2), end: str.endIndex.advancedBy(-1))) //"llo, playgroun" 

你也可以使用NSRange的NSString方法,但是你必须确保你使用的NSString是这样的:

 let myNSString = str as NSString myNSString.substringWithRange(NSRange(location: 0, length: 3)) 

注意:正如JanX2所提到的,第二种方法对于unicodestring是不安全的。

Swift 2

简单

 let str = "My String" let subStr = str[str.startIndex.advancedBy(3)...str.startIndex.advancedBy(7)] //"Strin" 

Swift 3

 let startIndex = str.index(str.startIndex, offsetBy: 3) let endIndex = str.index(str.startIndex, offsetBy: 7) str[startIndex...endIndex] // "Strin" str.substring(to: startIndex) // "My " str.substring(from: startIndex) // "String" 

斯威夫特4

substring(to:)substring(from:)Swift 4被弃用。

 String(str[..<startIndex]) // "My " String(str[startIndex...]) // "String" String(str[startIndex...endIndex]) // "Strin" 

注意:@airspeedswift在这种方法的权衡方面提出了一些非常有见地的观点 ,特别是隐藏的性能影响。 string不是简单的野兽,并且到一个特定的索引可能需要O(n)次,这意味着使用下标的循环可以是O(n ^ 2)。 你被警告了。

你只需要添加一个新的subscript函数,它需要一个范围,并使用advancedBy()来走到你想要的地方:

 import Foundation extension String { subscript (r: Range<Int>) -> String { get { let startIndex = self.startIndex.advancedBy(r.startIndex) let endIndex = startIndex.advancedBy(r.endIndex - r.startIndex) return self[Range(start: startIndex, end: endIndex)] } } } var s = "Hello, playground" println(s[0...5]) // ==> "Hello," println(s[0..<5]) // ==> "Hello" 

(这肯定是语言的一部分,请dupe rdar:// 17158813 )

为了好玩,你也可以在索引上加一个+运算符:

 func +<T: ForwardIndex>(var index: T, var count: Int) -> T { for (; count > 0; --count) { index = index.succ() } return index } s.substringWithRange(s.startIndex+2 .. s.startIndex+5) 

(我不知道这个是否应该成为该语言的一部分。)

在我写作的时候,没有任何扩展是完全兼容Swift 3的 ,所以这里覆盖了我所能想到的所有需求:

 extension String { func substring(from: Int?, to: Int?) -> String { if let start = from { guard start < self.characters.count else { return "" } } if let end = to { guard end >= 0 else { return "" } } if let start = from, let end = to { guard end - start >= 0 else { return "" } } let startIndex: String.Index if let start = from, start >= 0 { startIndex = self.index(self.startIndex, offsetBy: start) } else { startIndex = self.startIndex } let endIndex: String.Index if let end = to, end >= 0, end < self.characters.count { endIndex = self.index(self.startIndex, offsetBy: end + 1) } else { endIndex = self.endIndex } return self[startIndex ..< endIndex] } func substring(from: Int) -> String { return self.substring(from: from, to: nil) } func substring(to: Int) -> String { return self.substring(from: nil, to: to) } func substring(from: Int?, length: Int) -> String { guard length > 0 else { return "" } let end: Int if let start = from, start > 0 { end = start + length - 1 } else { end = length - 1 } return self.substring(from: from, to: end) } func substring(length: Int, to: Int?) -> String { guard let end = to, end > 0, length > 0 else { return "" } let start: Int if let end = to, end - length > 0 { start = end - length + 1 } else { start = 0 } return self.substring(from: start, to: to) } } 

然后,你可以使用:

 let string = "Hello,World!" 

string.substring(from: 1, to: 7)得到你: ello,Wo

string.substring(to: 7)得到你: Hello,Wo

string.substring(from: 3)得到你: lo,World!

string.substring(from: 1, length: 4)得到你:你好

string.substring(length: 4, to: 7)得到你: o,Wo

更新的substring(from: Int?, length: Int)支持从零开始。

SWIFT 2.0

简单:

 let myString = "full text container" let substring = myString[myString.startIndex..<myString.startIndex.advancedBy(3)] // prints: ful 

SWIFT 3.0

 let substring = myString[myString.startIndex..<myString.index(myString.startIndex, offsetBy: 3)] // prints: ful 

SWIFT 4.0

子string操作返回一个子stringtypes的实例,而不是string。

 let substring = myString[myString.startIndex..<myString.index(myString.startIndex, offsetBy: 3)] // prints: ful // Convert the result to a String for long-term storage. let newString = String(substring) 

一旦find正确的语法,它比这里的任何答案都简单得多。

我想拿走[和]

 let myString = "[ABCDEFGHI]" let startIndex = advance(myString.startIndex, 1) //advance as much as you like let endIndex = advance(myString.endIndex, -1) let range = startIndex..<endIndex let myNewString = myString.substringWithRange( range ) 

结果将是“ABCDEFGHI”startIndex和endIndex也可以用在

 let mySubString = myString.substringFromIndex(startIndex) 

等等!

PS:正如在备注中指出的那样,在xcode 7和iOS9中,swift 2中有一些语法变化!

请看这个页面

例如,以我的全名find第一个名字(到第一个空格):

 let name = "Joris Kluivers" let start = name.startIndex let end = find(name, " ") if end { let firstName = name[start..end!] } else { // no space found } 

startend的types是String.Index ,用于创build一个Range<String.Index>并用于下标访问器(如果在原始string中find空格)。

直接从开始文章中使用的整数位置创buildString.Index是很困难的。 这是因为在我的名字中,每个字符的大小都是相同的。 但是在其他语言中使用特殊口音的字符可能使用了多个字节(取决于所使用的编码)。 那么整数指的是什么字节呢?

可以使用succpred方法从现有的String.Index创build一个新的String.Index ,它将确保正确的字节数跳过到编码中的下一个代码点。 但在这种情况下,searchstring中第一个空格的索引以查找结束索引更容易。

由于String是NSString的桥梁types,所以“旧”方法应该可以工作,但是不清楚如何 – 例如,这也不起作用(看起来不是有效的语法):

  let x = str.substringWithRange(NSMakeRange(0, 3)) 

对我来说,这是你问题中非常有趣的部分。 string桥接到NSString,所以大多数 NSString方法直接在string上工作。 你可以自由地使用它们,而不用考虑。 所以,举个例子,就像你期望的那样:

 // delete all spaces from Swift String stateName stateName = stateName.stringByReplacingOccurrencesOfString(" ", withString:"") 

但是,正如经常发生的那样,“我得到了我的魔力,但这对你并不起作用。” 你碰巧select了一个平行命名的Swift方法存在的罕见情况之一,在这种情况下,Swift方法掩盖了Objective-C方法。 因此,当你说str.substringWithRange ,Swift认为你的意思是Swift方法,而不是NSString方法 – 然后你被弄糊涂了,因为Swift方法需要一个Range<String.Index> ,你不知道如何做其中一个。

简单的解决办法就是通过明确地施加压制来阻止Swift这样蒙上阴影:

 let x = (str as NSString).substringWithRange(NSMakeRange(0, 3)) 

请注意,这里不涉及重要的额外工作。 “演员”并不意味着“转换”; 该string实际上是一个NSString。 我们只是告诉Swift如何这个variables的目的这一行代码。

这整个事情真奇怪的部分是,导致所有这些麻烦的Swift方法是没有logging的。 我不知道它在哪里定义。 它不在NSString头文件中,也不在Swift头文件中。

简短的回答是,现在在Swift中确实很难。 我的直觉是,苹果公司在这方面还有很多工作要做。

String.substringWithRange()期望一个Range<String.Index>参数,并且据我所知,不存在String.Indextypes的生成器方法。 您可以从aString.startIndexaString.endIndex获取String.Index值, aString.startIndex aString.endIndex调用.succ().pred() ,但这是疯狂的。

如何在String类的扩展需要良好的旧的Int

 extension String { subscript (r: Range<Int>) -> String { get { let subStart = advance(self.startIndex, r.startIndex, self.endIndex) let subEnd = advance(subStart, r.endIndex - r.startIndex, self.endIndex) return self.substringWithRange(Range(start: subStart, end: subEnd)) } } func substring(from: Int) -> String { let end = countElements(self) return self[from..<end] } func substring(from: Int, length: Int) -> String { let end = from + length return self[from..<end] } } let mobyDick = "Call me Ishmael." println(mobyDick[8...14]) // Ishmael let dogString = "This 🐶's name is Patch." println(dogString[5..<6]) // 🐶 println(dogString[5...5]) // 🐶 println(dogString.substring(5)) // 🐶's name is Patch. println(dogString.substring(5, length: 1)) // 🐶 

更新: Swift beta 4解决了下面的问题!

按照[testing版3和更早的版本],甚至Swift原生string在处理Unicode字符方面也有一些问题。 上面的狗图标工作,但以下不:

 let harderString = "1:1️⃣" for character in harderString { println(character) } 

输出:

 1 : 1 ️ ⃣ 

在新的Xcode 7.0使用

 //: Playground - noun: a place where people can play import UIKit var name = "How do you use String.substringWithRange?" let range = name.startIndex.advancedBy(0)..<name.startIndex.advancedBy(10) name.substringWithRange(range) //OUT: 

在这里输入图像描述

你可以使用这个扩展来改进substringWithRange

Swift 2.3

 extension String { func substringWithRange(start: Int, end: Int) -> String { if (start < 0 || start > self.characters.count) { print("start index \(start) out of bounds") return "" } else if end < 0 || end > self.characters.count { print("end index \(end) out of bounds") return "" } let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(end)) return self.substringWithRange(range) } func substringWithRange(start: Int, location: Int) -> String { if (start < 0 || start > self.characters.count) { print("start index \(start) out of bounds") return "" } else if location < 0 || start + location > self.characters.count { print("end index \(start + location) out of bounds") return "" } let range = Range(start: self.startIndex.advancedBy(start), end: self.startIndex.advancedBy(start + location)) return self.substringWithRange(range) } } 

Swift 3

 extension String { func substring(start: Int, end: Int) -> String { if (start < 0 || start > self.characters.count) { print("start index \(start) out of bounds") return "" } else if end < 0 || end > self.characters.count { print("end index \(end) out of bounds") return "" } let startIndex = self.characters.index(self.startIndex, offsetBy: start) let endIndex = self.characters.index(self.startIndex, offsetBy: end) let range = startIndex..<endIndex return self.substring(with: range) } func substring(start: Int, location: Int) -> String { if (start < 0 || start > self.characters.count) { print("start index \(start) out of bounds") return "" } else if location < 0 || start + location > self.characters.count { print("end index \(start + location) out of bounds") return "" } let startIndex = self.characters.index(self.startIndex, offsetBy: start) let endIndex = self.characters.index(self.startIndex, offsetBy: start + location) let range = startIndex..<endIndex return self.substring(with: range) } } 

用法:

 let str = "Hello, playground" let substring1 = str.substringWithRange(0, end: 5) //Hello let substring2 = str.substringWithRange(7, location: 10) //playground 

示例代码,了解如何在Swift 2.0中获取子string

(i)从起始索引开始的子串

input: –

 var str = "Swift is very powerful language!" print(str) str = str.substringToIndex(str.startIndex.advancedBy(5)) print(str) 

输出: –

 Swift is very powerful language! Swift 

(ii)来自特定索引的子串

input: –

 var str = "Swift is very powerful language!" print(str) str = str.substringFromIndex(str.startIndex.advancedBy(6)).substringToIndex(str.startIndex.advancedBy(2)) print(str) 

输出: –

 Swift is very powerful language! is 

我希望它会帮助你!

简单的解决scheme,less量代码

做一个包括几乎所有其他语言都具有的基本子串的扩展:

 extension String { func subString(start: Int, end: Int) -> String { let startIndex = self.index(self.startIndex, offsetBy: start) let endIndex = self.index(startIndex, offsetBy: end) let finalString = self.substring(from: startIndex) return finalString.substring(to: endIndex) } } 

只需与此调用

 someString.subString(start: 0, end: 6) 

这在我的操场:)

 String(seq: Array(str)[2...4]) 

更新了Xcode 7.添加string扩展:

使用:

 var chuck: String = "Hello Chuck Norris" chuck[6...11] // => Chuck 

执行:

 extension String { /** Subscript to allow for quick String substrings ["Hello"][0...1] = "He" */ subscript (r: Range<Int>) -> String { get { let start = self.startIndex.advancedBy(r.startIndex) let end = self.startIndex.advancedBy(r.endIndex - 1) return self.substringWithRange(start..<end) } } } 

在操场上试试这个

 var str:String = "Hello, playground" let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,8)) 

它会给你你好,p”

然而,这真的很有趣的地方是,如果你使最后一个索引大于操场中的string,它将显示你在str之后定义的任何string:o

Range()似乎是一个通用函数,所以它需要知道它正在处理的types。

你还必须给它一个真正的string,你对操场感兴趣,因为它看起来像一个接一个地按顺序把所有的叮咬与之后的variables名称。

所以

 var str:String = "Hello, playground" var str2:String = "I'm the next string" let range = Range(start:advance(str.startIndex,1), end: advance(str.startIndex,49)) 

给出了“ello,playground`str I'mnextstring str2 ”

即使str2是用let定义的

🙂

Rob Napier已经用下标给出了一个很棒的答案。 但是我觉得有一个缺点就是没有检查出界限的条件。 这可能会导致崩溃。 所以我修改了扩展名,在这里

 extension String { subscript (r: Range<Int>) -> String? { //Optional String as return value get { let stringCount = self.characters.count as Int //Check for out of boundary condition if (stringCount < r.endIndex) || (stringCount < r.startIndex){ return nil } let startIndex = self.startIndex.advancedBy(r.startIndex) let endIndex = self.startIndex.advancedBy(r.endIndex - r.startIndex) return self[Range(start: startIndex, end: endIndex)] } } } 

下面的输出

 var str2 = "Hello, World" var str3 = str2[0...5] //Hello, var str4 = str2[0..<5] //Hello var str5 = str2[0..<15] //nil 

所以我build议总是检查一下,如果让

 if let string = str[0...5] { //Manipulate your string safely } 

Swift3中

例如:变数“公爵詹姆斯·托马斯”,我们需要得到“詹姆斯”。

 let name = "Duke James Thomas" let range: Range<String.Index> = name.range(of:"James")! let lastrange: Range<String.Index> = img.range(of:"Thomas")! var middlename = name[range.lowerBound..<lstrange.lowerBound] print (middlename) 

从罗布·纳皮尔(Rob Napier)的页面开始,我开发了这些常见的string扩展 ,其中两个是:

 subscript (r: Range<Int>) -> String { get { let startIndex = advance(self.startIndex, r.startIndex) let endIndex = advance(self.startIndex, r.endIndex - 1) return self[Range(start: startIndex, end: endIndex)] } } func subString(startIndex: Int, length: Int) -> String { var start = advance(self.startIndex, startIndex) var end = advance(self.startIndex, startIndex + length) return self.substringWithRange(Range<String.Index>(start: start, end: end)) } 

用法:

 "Awesome"[3...7] //"some" "Awesome".subString(3, length: 4) //"some" 

这是你如何得到一个string的范围:

 var str = "Hello, playground" let startIndex = advance(str.startIndex, 1) let endIndex = advance(startIndex, 8) let range = startIndex..<endIndex let substr = str[range] //"ello, pl" 

关键是你正在传递一个String.Indextypes的值的范围(这是什么预先返回),而不是整数。

之所以这么做是必要的,是因为Swift中的string没有随机存取(基本上是因为Unicode字符的长度可变)。 你也不能做str[1] 。 String.Index被devise用来处理它们的内部结构。

你可以用一个下标来创build一个扩展名,这样做对你来说是这样的,所以你可以传递一个整数范围(参见Rob Napier的答案 )。

我试图想出Pythonic。

这里所有的下标都很好,但是我真正需要的东西很简单的时候通常是我想从后面string.endIndex.advancedBy(-1) ,例如string.endIndex.advancedBy(-1)

它支持nil值,对于开始和结束索引,其中nil意思是索引在0开始, string.characters.count为结束。

 extension String { var subString: (Int?) -> (Int?) -> String { return { (start) in { (end) in let startIndex = start ?? 0 < 0 ? self.endIndex.advancedBy(start!) : self.startIndex.advancedBy(start ?? 0) let endIndex = end ?? self.characters.count < 0 ? self.endIndex.advancedBy(end!) : self.startIndex.advancedBy(end ?? self.characters.count) return startIndex > endIndex ? "" : self.substringWithRange(startIndex ..< endIndex) } } } } let dog = "Dog‼🐶" print(dog.subString(nil)(-1)) // Dog!! 

编辑

更优雅的解决scheme:

 public extension String { struct Substring { var start: Int? var string: String public subscript(end: Int?) -> String { let startIndex = start ?? 0 < 0 ? string.endIndex.advancedBy(start!) : string.startIndex.advancedBy(start ?? 0) let endIndex = end ?? string.characters.count < 0 ? string.endIndex.advancedBy(end!) : string.startIndex.advancedBy(end ?? string.characters.count) return startIndex > endIndex ? "" : string.substringWithRange(startIndex ..< endIndex) } } public subscript(start: Int?) -> Substring { return Substring(start: start, string: self) } } let dog = "Dog‼🐶" print(dog[nil][-1]) // Dog!! 

首先创build范围,然后是子string。 您可以使用fromIndex..<toIndex语法如下所示:

 let range = fullString.startIndex..<fullString.startIndex.advancedBy(15) // 15 first characters of the string let substring = fullString.substringWithRange(range) 

这里是一个例子,只有在整个url的videoID只有.ie(6oL687G0Iso)在迅速

 let str = "https://www.youtube.com/watch?v=6oL687G0Iso&list=PLKmzL8Ib1gsT-5LN3V2h2H14wyBZTyvVL&index=2" var arrSaprate = str.componentsSeparatedByString("v=") let start = arrSaprate[1] let rangeOfID = Range(start: start.startIndex,end:start.startIndex.advancedBy(11)) let substring = start[rangeOfID] print(substring) 
 let startIndex = text.startIndex var range = startIndex.advancedBy(1) ..< text.endIndex.advancedBy(-4) let substring = text.substringWithRange(range) 

完整的示例,你可以看到这里

显示这个效果很好: http://www.learnswiftonline.com/reference-guides/string-reference-guide-for-swift/

 var str = "abcd" str = str.substringToIndex(1) 

那么,我有同样的问题,并解决了“bridgeToObjectiveC()”函数:

 var helloworld = "Hello World!" var world = helloworld.bridgeToObjectiveC().substringWithRange(NSMakeRange(6,6)) println("\(world)") // should print World! 

请注意,在这个例子中,substringWithRange和NSMakeRange一起使用从索引6(字符“W”)开始并且在索引6 + 6位置(字符“!”)处结束的string部分

干杯。

你可以使用我写的https://bit.ly/JString的Swiftstring扩展中的任何子string方法。;

 var string = "hello" var sub = string.substringFrom(3) // or string[3...5] println(sub)// "lo" 

如果你有一个NSRange ,桥接到NSString无缝工作。 例如,我正在使用UITextFieldDelegate进行一些工作,我很快就想要计算新的string值是否应该replace范围。

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string) println("Got new string: ", newString) } 

String简单扩展

 extension String { func substringToIndex(index: Int) -> String { return self[startIndex...startIndex.advancedBy(min(index, characters.count - 1))] } } 

Swift 3.0

我决定对此有一点乐趣,并在String上产生一个扩展。 我可能不会正确地使用truncate这个词,而是在我实际执行的function中使用truncate这个词。

 extension String { func truncate(from initialSpot: Int, withLengthOf endSpot: Int) -> String? { guard endSpot > initialSpot else { return nil } guard endSpot + initialSpot <= self.characters.count else { return nil } let truncated = String(self.characters.dropFirst(initialSpot)) let lastIndex = truncated.index(truncated.startIndex, offsetBy: endSpot) return truncated.substring(to: lastIndex) } } let favGameOfThronesSong = "Light of the Seven" let word = favGameOfThronesSong.truncate(from: 1, withLengthOf: 4) // "ight"