Swift:如何获取字符从开始到最后一个索引的子string
我想学习最好的/最简单的方法,把一个string转换成另一个string,但只有一个子集,从一开始就进入一个字符的最后一个索引。
例如,将“www.stackoverflow.com”转换为“www.stackoverflow”。 什么代码片段会做到这一点,而且是最快的? (我希望这不会引起辩论,但我无法find如何处理Swift中的子string的好教训。
只是后退
最好的方法是将substringToIndex
合并到endIndex
属性和advance
全局函数中。
var string1 = "www.stackoverflow.com" var index1 = advance(string1.endIndex, -4) var substring1 = string1.substringToIndex(index1)
寻找从后面开始的string
使用rangeOfString
并将options
设置为.BackwardsSearch
var string2 = "www.stackoverflow.com" var index2 = string2.rangeOfString(".", options: .BackwardsSearch)?.startIndex var substring2 = string2.substringToIndex(index2!)
没有扩展,纯粹的惯用Swift
Swift 2.0
advance
现在是Index
的一部分,被称为advancedBy
。 你这样做:
var string1 = "www.stackoverflow.com" var index1 = string1.endIndex.advancedBy(-4) var substring1 = string1.substringToIndex(index1)
Swift 3.0
你不能在String
上调用advancedBy
,因为它具有可变大小的元素。 你必须使用index(_, offsetBy:)
。
var string1 = "www.stackoverflow.com" var index1 = string1.index(string1.endIndex, offsetBy: -4) var substring1 = string1.substring(to: index1)
很多东西都被重新命名了。 这些情况是用camelCase写的, startIndex
变成了lowerBound
。
var string2 = "www.stackoverflow.com" var index2 = string2.range(of: ".", options: .backwards)?.lowerBound var substring2 = string2.substring(to: index2!)
另外,我不会推荐强制展开index2
。 您可以使用可选的绑定或map
。 就个人而言,我更喜欢使用map
:
var substring3 = index2.map(string2.substring(to:))
斯威夫特4
Swift 3版本仍然有效,但现在可以使用索引范围的下标了:
let string1 = "www.stackoverflow.com" let index1 = string1.index(string1.endIndex, offsetBy: -4) let substring1 = string1[string1.startIndex..<index1]
第二种方法保持不变:
let string2 = "www.stackoverflow.com" let index2 = string2.range(of: ".", options: .backwards)?.lowerBound let substring3 = index2.map(string2.substring(to:))
Swift 3,XCode 8
由于advancedBy(Int)
不在使用String
的方法index(String.Index, Int)
。 看看这个String
扩展名:
public extension String { func substring(_ r: Range<Int>) -> String { let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound) let toIndex = self.index(self.startIndex, offsetBy: r.upperBound) return self.substring(with: Range<String.Index>(uncheckedBounds: (lower: fromIndex, upper: toIndex))) } }
例:
let str = "0😀123456789" print(str.substring(0..<3)) // prints 0😀1
以下是可能有用的更多方法:
public extension String { //right is the first encountered string after left func between(_ left: String, _ right: String) -> String? { guard let leftRange = range(of: left), let rightRange = range(of: right, options: .backwards) , left != right && leftRange.upperBound < rightRange.lowerBound else { return nil } let sub = self.substring(from: leftRange.upperBound) let closestToLeftRange = sub.range(of: right)! return sub.substring(to: closestToLeftRange.lowerBound) } var length: Int { get { return self.characters.count } } func substring(to : Int) -> String? { if (to >= length) { return nil } let toIndex = self.index(self.startIndex, offsetBy: to) return self.substring(to: toIndex) } func substring(from : Int) -> String? { if (from >= length) { return nil } let fromIndex = self.index(self.startIndex, offsetBy: from) return self.substring(from: fromIndex) } func substring(_ r: Range<Int>) -> String { let fromIndex = self.index(self.startIndex, offsetBy: r.lowerBound) let toIndex = self.index(self.startIndex, offsetBy: r.upperBound) return self.substring(with: Range<String.Index>(uncheckedBounds: (lower: fromIndex, upper: toIndex))) } func character(_ at: Int) -> Character { return self[self.index(self.startIndex, offsetBy: at)] } }
PS开发人员不得不处理String.Index
而不是纯Int
,这真是太奇怪了。 为什么我们应该打扰内部的String
机制,而不是简单的substring()
方法?
我会用下标( s[start..<end]
)来做:
Swift 2
let s = "www.stackoverflow.com" let start = s.startIndex let end = s.endIndex.advancedBy(-4) let substring = s[start..<end] // www.stackoverflow
Swift 3
let s = "www.stackoverflow.com" let start = s.startIndex let end = s.index(s.endIndex, offsetBy: -4) let substring = s[start..<end] // www.stackoverflow
例如,将“www.stackoverflow.com”转换为“www.stackoverflow”。 什么代码片段会做到这一点,而且是最快的?
它能更像Swift吗?
let myString = "www.stackoverflow.com".stringByDeletingPathExtension // "www.stackoverflow"
更新: Xcode 7.2.1•Swift 2.1.1
extension String { var nsValue: NSString { return self } } let myString = "www.stackoverflow.com".nsValue.stringByDeletingPathExtension // "www.stackoverflow"
这是我怎么做的。 你可以用同样的方法做,也可以使用这个代码来获得想法。
let s = "www.stackoverflow.com" s.substringWithRange(0..<s.lastIndexOf("."))
这里是我使用的扩展:
import Foundation extension String { var length: Int { get { return countElements(self) } } func indexOf(target: String) -> Int { var range = self.rangeOfString(target) if let range = range { return distance(self.startIndex, range.startIndex) } else { return -1 } } func indexOf(target: String, startIndex: Int) -> Int { var startRange = advance(self.startIndex, startIndex) var range = self.rangeOfString(target, options: NSStringCompareOptions.LiteralSearch, range: Range<String.Index>(start: startRange, end: self.endIndex)) if let range = range { return distance(self.startIndex, range.startIndex) } else { return -1 } } func lastIndexOf(target: String) -> Int { var index = -1 var stepIndex = self.indexOf(target) while stepIndex > -1 { index = stepIndex if stepIndex + target.length < self.length { stepIndex = indexOf(target, startIndex: stepIndex + target.length) } else { stepIndex = -1 } } return index } func substringWithRange(range:Range<Int>) -> String { let start = advance(self.startIndex, range.startIndex) let end = advance(self.startIndex, range.endIndex) return self.substringWithRange(start..<end) } }
信用albertbori /通用Swiftstring扩展
一般来说,我是一个强大的扩展支持者,特别是像string操作,search和切片的需求。
您可以使用这些扩展名:
Swift 2.3
extension String { func substringFromIndex(index: Int) -> String { if (index < 0 || index > self.characters.count) { print("index \(index) out of bounds") return "" } return self.substringFromIndex(self.startIndex.advancedBy(index)) } func substringToIndex(index: Int) -> String { if (index < 0 || index > self.characters.count) { print("index \(index) out of bounds") return "" } return self.substringToIndex(self.startIndex.advancedBy(index)) } 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(from index: Int) -> String { if (index < 0 || index > self.characters.count) { print("index \(index) out of bounds") return "" } return self.substring(from: self.characters.index(self.startIndex, offsetBy: index)) } func substring(to index: Int) -> String { if (index < 0 || index > self.characters.count) { print("index \(index) out of bounds") return "" } return self.substring(to: self.characters.index(self.startIndex, offsetBy: index)) } 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 string = "www.stackoverflow.com" let substring = string.substringToIndex(string.characters.count-4)
String
具有内build的子stringfunction:
extension String : Sliceable { subscript (subRange: Range<String.Index>) -> String { get } }
如果你想要的是“去一个字符的第一个索引”,你可以使用内build的find()
函数得到子string:
var str = "www.stackexchange.com" str[str.startIndex ..< find(str, ".")!] // -> "www"
要find最后的索引,我们可以实现findLast()
。
/// Returns the last index where `value` appears in `domain` or `nil` if /// `value` is not found. /// /// Complexity: O(\ `countElements(domain)`\ ) func findLast<C: CollectionType where C.Generator.Element: Equatable>(domain: C, value: C.Generator.Element) -> C.Index? { var last:C.Index? = nil for i in domain.startIndex..<domain.endIndex { if domain[i] == value { last = i } } return last } let str = "www.stackexchange.com" let substring = map(findLast(str, ".")) { str[str.startIndex ..< $0] } // as String? // if "." is found, substring has some, otherwise `nil`
添加:
也许, findLast
BidirectionalIndexType
专用版本更快:
func findLast<C: CollectionType where C.Generator.Element: Equatable, C.Index: BidirectionalIndexType>(domain: C, value: C.Generator.Element) -> C.Index? { for i in lazy(domain.startIndex ..< domain.endIndex).reverse() { if domain[i] == value { return i } } return nil }
你想从一个string的开始索引到其中一个字符的最后一个索引获得一个string的子string吗? 如果是这样,你可以select下面的Swift 2.0+方法之一。
需要Foundation
方法
获取包含一个字符最后一个索引的子string:
import Foundation let string = "www.stackoverflow.com" if let rangeOfIndex = string.rangeOfCharacterFromSet(NSCharacterSet(charactersInString: "."), options: .BackwardsSearch) { print(string.substringToIndex(rangeOfIndex.endIndex)) } // prints "www.stackoverflow."
获取不包含字符最后一个索引的子string:
import Foundation let string = "www.stackoverflow.com" if let rangeOfIndex = string.rangeOfCharacterFromSet(NSCharacterSet(charactersInString: "."), options: .BackwardsSearch) { print(string.substringToIndex(rangeOfIndex.startIndex)) } // prints "www.stackoverflow"
如果你需要重复这些操作,扩展String
可以是一个很好的解决scheme:
import Foundation extension String { func substringWithLastInstanceOf(character: Character) -> String? { if let rangeOfIndex = rangeOfCharacterFromSet(NSCharacterSet(charactersInString: String(character)), options: .BackwardsSearch) { return self.substringToIndex(rangeOfIndex.endIndex) } return nil } func substringWithoutLastInstanceOf(character: Character) -> String? { if let rangeOfIndex = rangeOfCharacterFromSet(NSCharacterSet(charactersInString: String(character)), options: .BackwardsSearch) { return self.substringToIndex(rangeOfIndex.startIndex) } return nil } } print("www.stackoverflow.com".substringWithLastInstanceOf(".")) print("www.stackoverflow.com".substringWithoutLastInstanceOf(".")) /* prints: Optional("www.stackoverflow.") Optional("www.stackoverflow") */
不需要Foundation
获取包含一个字符最后一个索引的子string:
let string = "www.stackoverflow.com" if let reverseIndex = string.characters.reverse().indexOf(".") { print(string[string.startIndex ..< reverseIndex.base]) } // prints "www.stackoverflow."
获取不包含字符最后一个索引的子string:
let string = "www.stackoverflow.com" if let reverseIndex = string.characters.reverse().indexOf(".") { print(string[string.startIndex ..< reverseIndex.base.advancedBy(-1)]) } // prints "www.stackoverflow"
如果你需要重复这些操作,扩展String
可以是一个很好的解决scheme:
extension String { func substringWithLastInstanceOf(character: Character) -> String? { if let reverseIndex = characters.reverse().indexOf(".") { return self[self.startIndex ..< reverseIndex.base] } return nil } func substringWithoutLastInstanceOf(character: Character) -> String? { if let reverseIndex = characters.reverse().indexOf(".") { return self[self.startIndex ..< reverseIndex.base.advancedBy(-1)] } return nil } } print("www.stackoverflow.com".substringWithLastInstanceOf(".")) print("www.stackoverflow.com".substringWithoutLastInstanceOf(".")) /* prints: Optional("www.stackoverflow.") Optional("www.stackoverflow") */
如果你知道索引,这里有一个简单的方法来得到一个子串:
let s = "www.stackoverflow.com" let result = String(s.characters.prefix(17)) // "www.stackoverflow"
如果您的索引超出string的长度,它不会崩溃应用程序:
let s = "short" let result = String(s.characters.prefix(17)) // "short"
这两个例子都是Swift 3准备好的 。
Swift 3:
extension String { /// the length of the string var length: Int { return self.characters.count } /// Get substring, eg "ABCDE".substring(index: 2, length: 3) -> "CDE" /// /// - parameter index: the start index /// - parameter length: the length of the substring /// /// - returns: the substring public func substring(index: Int, length: Int) -> String { if self.length <= index { return "" } let leftIndex = self.index(self.startIndex, offsetBy: index) if self.length <= index + length { return self.substring(from: leftIndex) } let rightIndex = self.index(self.endIndex, offsetBy: -(self.length - index - length)) return self.substring(with: leftIndex..<rightIndex) } /// Get substring, eg -> "ABCDE".substring(left: 0, right: 2) -> "ABC" /// /// - parameter left: the start index /// - parameter right: the end index /// /// - returns: the substring public func substring(left: Int, right: Int) -> String { if length <= left { return "" } let leftIndex = self.index(self.startIndex, offsetBy: left) if length <= right { return self.substring(from: leftIndex) } else { let rightIndex = self.index(self.endIndex, offsetBy: -self.length + right + 1) return self.substring(with: leftIndex..<rightIndex) } } }
你可以testing它如下:
print("test: " + String("ABCDE".substring(index: 2, length: 3) == "CDE")) print("test: " + String("ABCDE".substring(index: 0, length: 3) == "ABC")) print("test: " + String("ABCDE".substring(index: 2, length: 1000) == "CDE")) print("test: " + String("ABCDE".substring(left: 0, right: 2) == "ABC")) print("test: " + String("ABCDE".substring(left: 1, right: 3) == "BCD")) print("test: " + String("ABCDE".substring(left: 3, right: 1000) == "DE"))
func substr(myString: String, start: Int, clen: Int)->String { var index2 = string1.startIndex.advancedBy(start) var substring2 = string1.substringFromIndex(index2) var index1 = substring2.startIndex.advancedBy(clen) var substring1 = substring2.substringToIndex(index1) return substring1 } substr(string1, start: 3, clen: 5)
Swift 3
let string = "www.stackoverflow.com" let first3Characters = String(string.characters.prefix(3)) // www let lastCharacters = string.characters.dropFirst(4) // stackoverflow.com (it would be a collection) //or by index let indexOfFouthCharacter = olNumber.index(olNumber.startIndex, offsetBy: 4) let first3Characters = olNumber.substring(to: indexOfFouthCharacter) // www let lastCharacters = olNumber.substring(from: indexOfFouthCharacter) // .stackoverflow.com
好文章理解,为什么我们需要这个
我已经扩展了两个子string方法的string。 你可以使用from / to范围或from / length调用substring,如下所示:
var bcd = "abcdef".substring(1,to:3) var cde = "abcdef".substring(2,to:-2) var cde = "abcdef".substring(2,length:3) extension String { public func substring(from:Int = 0, var to:Int = -1) -> String { if to < 0 { to = self.length + to } return self.substringWithRange(Range<String.Index>( start:self.startIndex.advancedBy(from), end:self.startIndex.advancedBy(to+1))) } public func substring(from:Int = 0, length:Int) -> String { return self.substringWithRange(Range<String.Index>( start:self.startIndex.advancedBy(from), end:self.startIndex.advancedBy(from+length))) } }
对于Swift 2.0 ,就是这样的:
var string1 = "www.stackoverflow.com" var index1 = string1.endIndex.advancedBy(-4) var substring1 = string1.substringToIndex(index1)
Swift 2.0下面的代码是在XCode 7.2上testing的。 请参阅底部的附件截图
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() var mainText = "http://stackoverflow.com" var range = Range(start: mainText.startIndex.advancedBy(7), end: mainText.startIndex.advancedBy(24)) var subText = mainText.substringWithRange(range) //OR Else use below for LAST INDEX range = Range(start: mainText.startIndex.advancedBy(7), end: mainText.endIndex) subText = mainText.substringWithRange(range) } }
我修改了andrewz的post,使其与Swift 2.0兼容(也许Swift 3.0)。 在我看来,这个扩展是更容易理解和类似于其他语言 (如PHP) 可用 。
extension String { func length() -> Int { return self.lengthOfBytesUsingEncoding(NSUTF16StringEncoding) } func substring(from:Int = 0, to:Int = -1) -> String { var nto=to if nto < 0 { nto = self.length() + nto } return self.substringWithRange(Range<String.Index>( start:self.startIndex.advancedBy(from), end:self.startIndex.advancedBy(nto+1))) } func substring(from:Int = 0, length:Int) -> String { return self.substringWithRange(Range<String.Index>( start:self.startIndex.advancedBy(from), end:self.startIndex.advancedBy(from+length))) } }
这是一个在Swift中获取子string的简单方法
import UIKit var str = "Hello, playground" var res = NSString(string: str) print(res.substring(from: 4)) print(res.substring(to: 10))