Basically, I want to make a program where if you start typing a name, the app will recognize it from the database and fill in the name for you. To do this, if a person types a comma after finishing a name, the app will start recording what the next name is. If it matches as a substring of one of the names in the database, it will fill it in for the user. The issue is that I need to get what part of the name has been filled out so far after the last occurrence of the comma character in the textField string, but I don't know how. For example: User types: "Daniel, Joh" And the app fills in John for you. Thanks.
4 Answers
If you really want the characters after the last comma, you could use a regular expression:
let string = "Hamilton, A"
let regex = try! NSRegularExpression(pattern: ",\\s*(\\S[^,]*)$")
if let match = regex.firstMatch(in: string, range: string.nsRange), let result = string[match.range(at: 1)] {
// use `result` here
}
Where, in Swift 4:
extension String {
/// An `NSRange` that represents the full range of the string.
var nsRange: NSRange {
return NSRange(startIndex ..< endIndex, in: self)
}
/// Substring from `NSRange`
///
/// - Parameter nsRange: `NSRange` within the string.
/// - Returns: `Substring` with the given `NSRange`, or `nil` if the range can't be converted.
subscript(nsRange: NSRange) -> Substring? {
return Range(nsRange, in: self)
.flatMap { self[$0] }
}
}
3 Comments
dhruvm
Does the regex solution also work if there are more than 2 names on the list?
dhruvm
Sorry I'm just asking because it says firstMatchInString not last. Thanks
Rob
OK, I understand the confusion. But if you look at my regex string, the last character is a
$, which says "match for the end of the string". Thus, you'll get only one match, the one at the end (if any). I only use firstMatchInString because, since we're only getting the last one, there's no need to enumerate through, but rather just grab the "first" match at the end of the string.Many thanks to Rob. We can even extend his String extension by including the full answer to the initial question, with any Character:
extension String {
func substringAfterLastOccurenceOf(_ char: Character) -> String {
let regex = try! NSRegularExpression(pattern: "\(char)\\s*(\\S[^\(char)]*)$")
if let match = regex.firstMatch(in: self, range: self.nsRange), let result = self[match.range(at: 1)] {
return String(result)
}
return ""
}
// ... Rob's String extension
}
So we just need to call:
let subStringAfterLastComma = "Hamilton, A".substringAfterLastOccurenceOf(",")
2 Comments
Paul Spiesberger
Not working any more:
Value of type 'String' has no member 'nsRange'atultw
@PaulSpiesberger you need to include rob's extension too, then it will work
Simple solution with range(of and options regularExpression and backwards.
It searches for a comma followed by an optional whitespace character.
extension String {
var subStringAfterLastComma : String {
guard let subrange = self.range(of: ",\\s?", options: [.regularExpression, .backwards]) else { return self }
return String(self[subrange.upperBound...])
}
}
let string1 = "Dan".subStringAfterLastComma // "Dan"
let string2 = "Daniel, Joh".subStringAfterLastComma // "Joh"
Comments
Thanks to Rob and Thierry G.
extension String {
var nsRange: NSRange {
return Foundation.NSRange(startIndex ..< endIndex, in: self)
}
subscript(nsRange: NSRange) -> Substring? {
return Range(nsRange, in: self)
.flatMap { self[$0] }
}
func substringAfterLastOccurenceOf(_ char: Character) -> String {
let regex = try! NSRegularExpression(pattern: "\(char)\\s*(\\S[^\(char)]*)$")
if let match = regex.firstMatch(in: self, range: self.nsRange), let result = self[match.range(at: 1)] {
return String(result)
}
return ""
}
}
we can use like this
let subStringAfterLastComma = "Hamilton, A".substringAfterLastOccurenceOf(",")