Posts: 0
Threads: 0
Joined: Oct 2019
Reputation:
0
Level: inf [ ]
Total Points: inf
Rank nan / 1
100% to upload Level
Activity inf / 1
99% to upload your Rank
Experience nan
100% to upload Experience
Points: 50
|
I am getting a string from html parse that is;
string = "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
my code is something like
var startIndex = text.rangeOfString("'")
var endIndex = text.rangeOfString("',")
var range2 = startIndex2...endIndex
substr= string.substringWithRange(range)
i am not sure if my second splitting string should be "'" or "',"
i want my outcome as
substr = "Info/99/something"
|
Posts: 0
Threads: 0
Joined: Jul 2019
Reputation:
0
Level: inf [ ]
Total Points: inf
Rank nan / 1
100% to upload Level
Activity inf / 1
99% to upload your Rank
Experience nan
100% to upload Experience
Points: 50
|
**Swift 5**
```
extension String {
/// Returns an array of substrings between the specified left and right strings.
/// Returns an empty array when there are no matches.
func substring(from left: String, to right: String) -> [String] {
// Escape special characters in the left and right strings for use in a regular expression
let leftEscaped = NSRegularExpression.escapedPattern(for: left)
let rightEscaped = NSRegularExpression.escapedPattern(for: right)
// Create a regular expression pattern to match content between the last occurrence of the left string
// and the right string
let pattern = "\(leftEscaped).*(?<=\(leftEscaped))(.*?)(?=\(rightEscaped))"
// Create a regular expression object with the pattern
guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else {
return []
}
// Find matches in the current string
let matches = regex.matches(in: self, options: [], range: NSRange(startIndex..., in: self))
// Extract the substrings from the matches and return them in an array
return matches.compactMap { match in
guard let range = Range(match.range(at: 1), in: self) else { return nil }
return String(self[range])
}
}
}
// Example usage
let result = "cat cat dog rat".substring(from: "cat", to: "rat")
print(result) // Output: [" dog "]
```
|
Posts: 0
Threads: 0
Joined: Jul 2018
Reputation:
0
Level: inf [ ]
Total Points: inf
Rank nan / 1
100% to upload Level
Activity inf / 1
99% to upload your Rank
Experience nan
100% to upload Experience
Points: 50
|
In Swift 4 or later you can create an extension method on StringProtocol to support substrings as well. You can just return a `Substring` instead of a new String:
edit/update: **Swift 5 or later**
extension StringProtocol {
func substring<S: StringProtocol>(from start: S, options: String.CompareOptions = []) -> SubSequence? {
guard let lower = range(of: start, options: options)?.upperBound
else { return nil }
return self[lower...]
}
func substring<S: StringProtocol>(through end: S, options: String.CompareOptions = []) -> SubSequence? {
guard let upper = range(of: end, options: options)?.upperBound
else { return nil }
return self[..<upper]
}
func substring<S: StringProtocol>(upTo end: S, options: String.CompareOptions = []) -> SubSequence? {
guard let upper = range(of: end, options: options)?.lowerBound
else { return nil }
return self[..<upper]
}
func substring<S: StringProtocol, T: StringProtocol>(from start: S, upTo end: T, options: String.CompareOptions = []) -> SubSequence? {
guard let lower = range(of: start, options: options)?.upperBound,
let upper = self[lower...].range(of: end, options: options)?.lowerBound
else { return nil }
return self[lower..<upper]
}
func substring<S: StringProtocol, T: StringProtocol>(from start: S, through end: T, options: String.CompareOptions = []) -> SubSequence? {
guard let lower = range(of: start, options: options)?.upperBound,
let upper = self[lower...].range(of: end, options: options)?.upperBound
else { return nil }
return self[lower..<upper]
}
}
***
Usage:
let string = "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
let substr = string.substring(from: "'") // "Info/99/something', 'City Hall',1, 99);"
let through = string.substring(through: "Info") // "javascript:getInfo"
let upTo = string.substring(upTo: "Info") // "javascript:get"
let fromUpTo = string.substring(from: "'", upTo: "',") // "Info/99/something"
let fromThrough = string.substring(from: "'", through: "',") // "Info/99/something',"
let fromUpToCaseInsensitive = string.substring(from: "'info/", upTo: "/something", options: .caseInsensitive) // "99"
|
Posts: 0
Threads: 0
Joined: Jun 2020
Reputation:
0
Level: inf [ ]
Total Points: inf
Rank nan / 1
100% to upload Level
Activity inf / 1
99% to upload your Rank
Experience nan
100% to upload Experience
Points: 50
|
If you want to support also from the start or end of the string
extension String {
func slice(from: String, to: String) -> String? {
return (from.isEmpty ? startIndex..<startIndex : range(of: from)).flatMap { fromRange in
(to.isEmpty ? endIndex..<endIndex : range(of: to, range: fromRange.upperBound..<endIndex)).map({ toRange in
String(self[fromRange.upperBound..<toRange.lowerBound])
})
}
}
}
"javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
.slice(from: "'", to: "',") // "Info/99/something"
"javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
.slice(from: "", to: ":") // "javascript"
"javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
.slice(from: ":", to: "") // "getInfo(1,'Info/99/something', 'City Hall',1, 99);"
"javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
.slice(from: "", to: "") // "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
----------
if you want another syntax, maybe more readable
extension String {
func slice(from: String, to: String) -> String? {
guard let fromRange = from.isEmpty ? startIndex..<startIndex : range(of: from) else { return nil }
guard let toRange = to.isEmpty ? endIndex..<endIndex : range(of: to, range: fromRange.upperBound..<endIndex) else { return nil }
return String(self[fromRange.upperBound..<toRange.lowerBound])
}
}
|
Posts: 0
Threads: 0
Joined: Feb 2017
Reputation:
0
Level: inf [ ]
Total Points: inf
Rank nan / 1
100% to upload Level
Activity inf / 1
99% to upload your Rank
Experience nan
100% to upload Experience
Points: 50
|
I rewrote [one of the top Swift answers]( [To see links please register here] ) to understand what it was doing with `map`. I prefer a version using `guard`, IMO.
```swift
extension String {
func slice(from: String, to: String) -> String? {
guard let rangeFrom = range(of: from)?.upperBound else { return nil }
guard let rangeTo = self[rangeFrom...].range(of: to)?.lowerBound else { return nil }
return String(self[rangeFrom..<rangeTo])
}
}
```
behavior:
```
let test1 = "a[b]c".slice(from: "[", to: "]") // "b"
let test2 = "abc".slice(from: "[", to: "]") // nil
let test3 = "a]b[c".slice(from: "[", to: "]") // nil
let test4 = "[a[b]c]".slice(from: "[", to: "]") // "a[b"
```
|
Posts: 0
Threads: 0
Joined: Apr 2018
Reputation:
0
Level: inf [ ]
Total Points: inf
Rank nan / 1
100% to upload Level
Activity inf / 1
99% to upload your Rank
Experience nan
100% to upload Experience
Points: 50
|
To find all substrings that are between a starting string and an ending string:
extension String {
func sliceMultipleTimes(from: String, to: String) -> [String] {
components(separatedBy: from).dropFirst().compactMap { sub in
(sub.range(of: to)?.lowerBound).flatMap { endRange in
String(sub[sub.startIndex ..< endRange])
}
}
}
}
let str = "start A end ... start B end"
str.sliceMultipleTimes(from: "start", to: "end") // ["A", "B"]
|
Posts: 0
Threads: 0
Joined: May 2018
Reputation:
0
Level: inf [ ]
Total Points: inf
Rank nan / 1
100% to upload Level
Activity inf / 1
99% to upload your Rank
Experience nan
100% to upload Experience
Points: 50
|
extension String {
func slice(from: String, to: String) -> String? {
return (range(of: from)?.upperBound).flatMap { substringFrom in
(range(of: to, range: substringFrom..<endIndex)?.lowerBound).map { substringTo in
String(self[substringFrom..<substringTo])
}
}
}
}
"javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
.sliceFrom("'", to: "',")
|
Posts: 0
Threads: 0
Joined: Sep 2020
Reputation:
0
Level: inf [ ]
Total Points: inf
Rank nan / 1
100% to upload Level
Activity inf / 1
99% to upload your Rank
Experience nan
100% to upload Experience
Points: 50
|
Swift 4 version of @litso. To find all values in text
func find(inText text: String, pattern: String) -> [String]? {
do {
let regex = try NSRegularExpression(pattern: pattern, options: .caseInsensitive)
let result = regex.matches(in: text, options: .init(rawValue: 0), range: NSRange(location: 0, length: text.count))
let matches = result.map { result in
return (text as NSString).substring(with: result.range)
}
return matches
} catch {
print(error)
}
return nil
}
|
Posts: 0
Threads: 0
Joined: Jan 2017
Reputation:
0
Level: inf [ ]
Total Points: inf
Rank nan / 1
100% to upload Level
Activity inf / 1
99% to upload your Rank
Experience nan
100% to upload Experience
Points: 50
|
Swift 4.2:
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)
,leftRange.upperBound <= rightRange.lowerBound else { return nil }
let sub = self[leftRange.upperBound...]
let closestToLeftRange = sub.range(of: right)!
return String(sub[..<closestToLeftRange.lowerBound])
}
}
|
Posts: 0
Threads: 0
Joined: May 2022
Reputation:
0
Level: inf [ ]
Total Points: inf
Rank nan / 1
100% to upload Level
Activity inf / 1
99% to upload your Rank
Experience nan
100% to upload Experience
Points: 50
|
I'd use a regular expression to extract substrings from complex input like this.
Swift 3.1:
<!-- language: lang-swift -->
let test = "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
if let match = test.range(of: "(?<=')[^']+", options: .regularExpression) {
print(test.substring(with: match))
}
// Prints: Info/99/something
Swift 2.0:
<!-- language: lang-swift -->
let test = "javascript:getInfo(1,'Info/99/something', 'City Hall',1, 99);"
if let match = test.rangeOfString("(?<=')[^']+", options: .RegularExpressionSearch) {
print(test.substringWithRange(match))
}
// Prints: Info/99/something
|
|