Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use regex with Swift?

Tags:

regex

swift

I am making an app in Swift and I need to catch 8 numbers from a string. Here's the string: index.php?page=index&l=99182677

My pattern is: &l=(\d{8,})

And here's my code:

var yourAccountNumber = "index.php?page=index&l=99182677"
let regex = try! NSRegularExpression(pattern: "&l=(\\d{8,})", options: NSRegularExpressionOptions.CaseInsensitive)
let range = NSMakeRange(0, yourAccountNumber.characters.count)
let match = regex.matchesInString(yourAccountNumber, options: NSMatchingOptions.Anchored, range: range)

Firstly, I don't know what the NSMatchingOptions means, on the official Apple library, I don't get all the .Anchored, .ReportProgress, etc stuff. Anyone would be able to lighten me up on this?

Then, when I print(match), nothing seems to contain on that variable ([]).

I am using Xcode 7 Beta 3, with Swift 2.0.

like image 782
Anthony Avatar asked Jul 12 '15 14:07

Anthony


People also ask

Does Swift have regex?

Swift Regex can also be used in Swift's pattern matching syntax in control flow statements: switch "abc" { case /\w+/: print("It's a word!") } Foundation also has regex support, it can be used for: formatters.

What is regex in iOS?

A regex ( also known as regular expressions) is a pattern string. These pattern strings allow you to search specific patterns in documents and to validate email, phone number etc. In iOS and MacOS regex been handled by NSRegularExpression .

What is difference [] and () in regex?

[] denotes a character class. () denotes a capturing group. [a-z0-9] -- One character that is in the range of a-z OR 0-9.


1 Answers

ORIGINAL ANSWER

Here is a function you can leverage to get captured group texts:

import Foundation

extension String {
    func firstMatchIn(string: NSString!, atRangeIndex: Int!) -> String {
        var error : NSError?
        let re = NSRegularExpression(pattern: self, options: .CaseInsensitive, error: &error)
        let match = re.firstMatchInString(string, options: .WithoutAnchoringBounds, range: NSMakeRange(0, string.length))
        return string.substringWithRange(match.rangeAtIndex(atRangeIndex))
    }
}

And then:

var result = "&l=(\\d{8,})".firstMatchIn(yourAccountNumber, atRangeIndex: 1)

The 1 in atRangeIndex: 1 will extract the text captured by (\d{8,}) capture group.

NOTE1: If you plan to extract 8, and only 8 digits after &l=, you do not need the , in the limiting quantifier, as {8,} means 8 or more. Change to {8} if you plan to capture just 8 digits.

NOTE2: NSMatchingAnchored is something you would like to avoid if your expected result is not at the beginning of a search range. See documentation:

Specifies that matches are limited to those at the start of the search range.

NOTE3: Speaking about "simplest" things, I'd advise to avoid using look-arounds whenever you do not have to. Look-arounds usually come at some cost to performance, and if you are not going to capture overlapping text, I'd recommend to use capture groups.

UPDATE FOR SWIFT 2

I have come up with a function that will return all matches with all capturing groups (similar to preg_match_all in PHP). Here is a way to use it for your scenario:

func regMatchGroup(regex: String, text: String) -> [[String]] {
do {
    var resultsFinal = [[String]]()
    let regex = try NSRegularExpression(pattern: regex, options: [])
    let nsString = text as NSString
    let results = regex.matchesInString(text,
        options: [], range: NSMakeRange(0, nsString.length))
    for result in results {
        var internalString = [String]()
        for var i = 0; i < result.numberOfRanges; ++i{
            internalString.append(nsString.substringWithRange(result.rangeAtIndex(i)))
        }
        resultsFinal.append(internalString)
    }
    return resultsFinal
   } catch let error as NSError {
       print("invalid regex: \(error.localizedDescription)")
       return [[]]
   }
}
// USAGE:
let yourAccountNumber = "index.php?page=index&l=99182677"
let matches = regMatchGroup("&l=(\\d{8,})", text: yourAccountNumber)
if (matches.count > 0) // If we have matches....
{ 
    print(matches[0][1]) //  Print the first one, Group 1.
}
like image 134
Wiktor Stribiżew Avatar answered Sep 20 '22 10:09

Wiktor Stribiżew