Index of a substring in a string with Swift
edit/update:
Xcode 11.4 • Swift 5.2 or later
import Foundationextension StringProtocol { func index<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> Index? { range(of: string, options: options)?.lowerBound } func endIndex<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> Index? { range(of: string, options: options)?.upperBound } func indices<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> [Index] { ranges(of: string, options: options).map(\.lowerBound) } func ranges<S: StringProtocol>(of string: S, options: String.CompareOptions = []) -> [Range<Index>] { var result: [Range<Index>] = [] var startIndex = self.startIndex while startIndex < endIndex, let range = self[startIndex...] .range(of: string, options: options) { result.append(range) startIndex = range.lowerBound < range.upperBound ? range.upperBound : index(range.lowerBound, offsetBy: 1, limitedBy: endIndex) ?? endIndex } return result }}
usage:
let str = "abcde"if let index = str.index(of: "cd") { let substring = str[..<index] // ab let string = String(substring) print(string) // "ab\n"}
let str = "Hello, playground, playground, playground"str.index(of: "play") // 7str.endIndex(of: "play") // 11str.indices(of: "play") // [7, 19, 31]str.ranges(of: "play") // [{lowerBound 7, upperBound 11}, {lowerBound 19, upperBound 23}, {lowerBound 31, upperBound 35}]
case insensitive sample
let query = "Play"let ranges = str.ranges(of: query, options: .caseInsensitive)let matches = ranges.map { str[$0] } //print(matches) // ["play", "play", "play"]
regular expression sample
let query = "play"let escapedQuery = NSRegularExpression.escapedPattern(for: query)let pattern = "\\b\(escapedQuery)\\w+" // matches any word that starts with "play" prefixlet ranges = str.ranges(of: pattern, options: .regularExpression)let matches = ranges.map { str[$0] }print(matches) // ["playground", "playground", "playground"]
Using String[Range<String.Index>]
subscript you can get the sub string. You need starting index and last index to create the range and you can do it as below
let str = "abcde"if let range = str.range(of: "cd") { let substring = str[..<range.lowerBound] // or str[str.startIndex..<range.lowerBound] print(substring) // Prints ab}else { print("String not present")}
If you don't define the start index this operator ..<
, it take the starting index. You can also use str[str.startIndex..<range.lowerBound]
instead of str[..<range.lowerBound]
Swift 5
Find index of substring
let str = "abcdecd"if let range: Range<String.Index> = str.range(of: "cd") { let index: Int = str.distance(from: str.startIndex, to: range.lowerBound) print("index: ", index) //index: 2}else { print("substring not found")}
Find index of Character
let str = "abcdecd"if let firstIndex = str.firstIndex(of: "c") { let index = str.distance(from: str.startIndex, to: firstIndex) print("index: ", index) //index: 2}else { print("symbol not found")}