Reputation: 10744
A string:
"[email protected], [email protected], [email protected], [email protected]"
Through gesture recognizer, I am able to get the character the user tapped on (happy to provide code, but don't see the relevance at this point).
Let's say the User tapped on o
in "[email protected]"
and the character index
is 39
Given 39
the index
of o
, I would like to get the string start index of c
where "[email protected]"
begins, and an end index
for m
from "com"
where "[email protected]"
ends.
In another words, given an index
of a character
in a String
, I need to get the index
on the left
and right
right before we encounter a space in a String
on the left and a comma
on the right.
Tried, but this only provides the last word in the String:
if let range = text.range(of: " ", options: .backwards) {
let suffix = String(text.suffix(from: range.upperBound))
print(suffix) // [email protected]
}
I am not sure where to go from here?
Upvotes: 2
Views: 2229
Reputation: 539735
You can call range(of:)
on two slices of the given string:
text[..<index]
is the text preceding the given character position,
and text[index...]
is the text starting at the given position.
Example:
let text = "[email protected], [email protected], [email protected], [email protected]"
let index = text.index(text.startIndex, offsetBy: 39)
// Search the space before the given position:
let start = text[..<index].range(of: " ", options: .backwards)?.upperBound ?? text.startIndex
// Search the comma after the given position:
let end = text[index...].range(of: ",")?.lowerBound ?? text.endIndex
print(text[start..<end]) // [email protected]
Both range(of:)
calls return nil
if no space (or comma) has
been found. In that case the nil-coalescing operator ??
is used
to get the start (or end) index instead.
(Note that this works because Substring
s share a common index
with their originating string.)
An alternative approach is to use a "data detector", so that the URL detection does not depend on certain separators.
Example (compare How to detect a URL in a String using NSDataDetector):
let text = "[email protected], [email protected], [email protected], [email protected]"
let index = text.index(text.startIndex, offsetBy: 39)
let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
let matches = detector.matches(in: text, range: NSRange(location: 0, length: text.utf16.count))
for match in matches {
if let range = Range(match.range, in: text), range.contains(index) {
print(text[range])
}
}
Upvotes: 5
Reputation: 285079
Different approach:
You have the string and the Int
index
let string = "[email protected], [email protected], [email protected], [email protected]"
let characterIndex = 39
Get the String.Index
from the Int
let stringIndex = string.index(string.startIndex, offsetBy: characterIndex)
Convert the string into an array of addresses
let addresses = string.components(separatedBy: ", ")
Map the addresses to their ranges (Range<String.Index>
) in the string
let ranges = addresses.map{string.range(of: $0)!}
Get the (Int
) index of the range which contains stringIndex
if let index = ranges.index(where: {$0.contains(stringIndex)}) {
Get the corresponding address
let address = addresses[index] }
Upvotes: 2
Reputation: 51891
One approach could be to split the original string on the “,” and then using simple math to find in what element of the array the given position (39) exist and from there get the right string or indexes for the previous space and next comma depending on what your end goal is.
Upvotes: 0