Search code examples
swiftregexstringsubstringnsregularexpression

Retrieve array of substring matched with regex in swift


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]()
        }
    }
}

Solution

  • 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
    }