你如何使用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中查找字符索引 )似乎表明,由于String
是NSString
的桥接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 }
start
和end
的types是String.Index
,用于创build一个Range<String.Index>
并用于下标访问器(如果在原始string中find空格)。
直接从开始文章中使用的整数位置创buildString.Index
是很困难的。 这是因为在我的名字中,每个字符的大小都是相同的。 但是在其他语言中使用特殊口音的字符可能使用了多个字节(取决于所使用的编码)。 那么整数指的是什么字节呢?
可以使用succ
和pred
方法从现有的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.Index
types的生成器方法。 您可以从aString.startIndex
和aString.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"