Convert a JavaScript Regex to a Swift Regex
Asked Answered
E

1

1

I'm learning Swift, and I'm trying to convert a small bit of JavaScript code to Swift. The JavaScript code uses a Regex to split up a string, as shown below:

var text = "blah.clah##something_else";
var parts = text.match(/(^.*?)\#\#(.+$)/);

after execution, the parts array will then contain the following:

["blah.clah##something_else", "blah.clah", "something_else"]

I would like to replicate the same behavior in Swift. Below is the Swift code I've written to do split up a String into a String array using a Regex:

func matchesForRegexInText(regex: String!, text: String!) -> [String] {
do {
    let regex = try NSRegularExpression(pattern: regex, options: NSRegularExpressionOptions.CaseInsensitive)
    let nsString = text as NSString
    let results = regex.matchesInString(text,
        options: NSMatchingOptions.ReportCompletion , range: NSMakeRange(0, nsString.length))
        as [NSTextCheckingResult]
    return results.map({
        nsString.substringWithRange($0.range)
    })
} catch {
    print("exception")
    return [""]
}

}

When I call the above function with the following:

matchesForRegexInText("(^.*?)\\#\\#(.+$)", text: "blah.clah##something_else")

I get the following:

["blah.clah##something_else"]

I've tried a number of different Regex's without success. Is the Regex (^.*?)\#\#(.+$) correct, or is there a problem with the matchesForRegexInText() function? I appreciate any insight.

I'm using Swift 2, and Xcode Version 7.0 beta (7A120f)

Encasement answered 28/6, 2015 at 18:41 Comment(2)
What if you try let results = regex.matchesInString(text, options: NSMatchingOptions.ReportCompletion, range: NSMakeRange(0, nsString.length)) as Array<NSTextCheckingResult>? I think the main issue is that you only pass the zeroth group to the array you create with nsString.substringWithRange($0.range) (i.e. just $0th group, the whole match). And you do not need to escape #s.Imide
Thanks for suggestion. I made the changes but it didn't change the output (it's still ["blah.clah##something_else"]). I also added a print(results.count) before the return to print out the number of elements in the array, and it is 1.Encasement
T
5

As already mentioned in a comment, your pattern matches the entire string, so regex.matchesInString() returns a single NSTextCheckingResult whose range describes the entire string. What you are looking for are the substrings matching the capture groups in your pattern. These are available as rangeAtIndex(i) with i >= 1:

func matchesForRegexInText(regex: String!, text: String!) -> [String] {

    do {
        let regex = try NSRegularExpression(pattern: regex, options: [])
        let nsString = text as NSString
        guard let result = regex.firstMatchInString(text, options: [], range: NSMakeRange(0, nsString.length)) else {
            return [] // pattern does not match the string
        }
        return (1 ..< result.numberOfRanges).map {
            nsString.substringWithRange(result.rangeAtIndex($0))
        }
    } catch let error as NSError {
        print("invalid regex: \(error.localizedDescription)")
        return []
    }
}

Example:

let matches = matchesForRegexInText("(^.*?)##(.+$)", text: "blah.clah##something_else")
print(matches)
// [blah.clah, something_else]
Tiffanietiffanle answered 28/6, 2015 at 20:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.