Search code examples
iosswiftstringsubstringcharacter

Swift Get substring after last occurrence of character in string


I am creating a post upload page that needs to detect when the user types the "@" symbol so it can search the database for the username. My code works for the first "@" in the string but does not work for any additional ones. I want the user to be able to tag as many usernames as they would like. For example: Hey @John did you talk to @Jim today?

This is what I am looking for but it is out of date: How to get substring after last occurrence of character in string: Swift IOS

current code:

var afterEqualsTo = ""
if let index = text.range(of: "@")?.upperBound {
    let afterEqualsTo = String(text.suffix(from: index))
    print(afterEqualsTo)
}

Solution

  • You can use BidirectionalCollection method lastIndex(of: Element) and get the substring from there and drop the first character:

    let text = "Hello, playground! Hello World!!!"
    if let index = text.lastIndex(of: " ") {
        let afterEqualsTo = String(text.suffix(from: index).dropFirst())
        print(afterEqualsTo)
    }
    

    Another option is to use options backwards when using range of string as you tried above:

    let text = "Hello, playground! Hello World!!!"
    if let index = text.range(of: " ", options: .backwards)?.upperBound {
        let afterEqualsTo = String(text.suffix(from: index))
        print(afterEqualsTo)  // "World!!!\n"
    }
    

    If you would like to get all users in your string you should use a regex like "@\w+\b" and iterate over your whole string. if you want to exclude the character @ from your results you can use a positive lookbehind pattern like "(?<=@)\w+\b"

    let text = "Hey @John did you talk to @Jim today?"
    var ranges: [Range<String.Index>] = []
    var start = text.startIndex
    let pattern = #"@\w+\b"#
    while start < text.endIndex,
        let range = text[start...].range(of: pattern, options: .regularExpression) {
        ranges.append(range)
        start = text.index(range.upperBound, offsetBy: 1, limitedBy: text.endIndex) ?? text.endIndex
    }
    
    let users = ranges.map { text[$0] }
    users  // ["@John", "@Jim"]
    

    or using the positive lookbehind pattern "(?<=@)\w+\b"

    users  // ["John", "Jim"]