0

Is there any way to retrieve an array of words prefixed with @ sign in a string?

"@City == xyz AND @Hobby == gardening" -> ["@City","@Hobby"]

I tried below two methods but both are returning an empty array.

let regexp = "/@\\w*/g"

func matches(for regex: String, in text: String) -> [String] {
    do {
        let regex = try NSRegularExpression(pattern: regex)
        let results = regex.matches(in: text,range: NSRange(text.startIndex..., in: text))
        return results.map {
            String(text[Range($0.range, in: text)!])
        }
    } catch let error {
        print("invalid regex: \(error.localizedDescription)")
        return []
    }
}

extension String {
    func regex (pattern: String) -> [String] {
        do {
            let regex = try NSRegularExpression(pattern: pattern, options: NSRegularExpression.Options(rawValue: 0))
            let nsstr = self as NSString
            let all = NSRange(location: 0, length: nsstr.length)
            var matches : [String] = [String]()
            regex.enumerateMatches(in: self, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: all) {
                (result : NSTextCheckingResult?, _, _) in
                if let r = result {
                    let result = nsstr.substring(with: r.range) as String
                    matches.append(result)
                }
            }
            return matches
        } catch {
            return [String]()
        }
    }
}
2
  • 2
    let regexp = "@\\w*" Commented May 6, 2022 at 3:56
  • @JoakimDanielson: Yes they both are connected. I want a generic solution as the condition is random and could be any. Commented May 6, 2022 at 12:05

2 Answers 2

4

Your fundamental issue, as @jnpdx hinted at in a comment, is that your regexp string contains control elements from another language. The following should solve your issue:

let regexp = "@\\w*"

You also get bogged down in unnecessary try-catch statements and outdated APIs based on Objective-C and their related type conversions. The following should do:

func matches(for regex: String, in text: String) -> [String] {
    var result = [String]()
    var startIndex = text.startIndex
    let endIndex = text.endIndex
    while let range = text.range(of: regex,
                                 options: .regularExpression,
                                 range: startIndex ..< endIndex)
    {
        result.append(String(text[range]))
        startIndex = range.upperBound
    }
    return result
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the swift version of the code.
1

On iOS 16+ you can also write like this.

let text = "@City == xyz AND @Hobby == gardening"
let regex = /@\w*/

let matches = text.matches(of: regex)
let results = matches.map { String($0.output) }

print(results) // ["@City", "@Hobby"]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.