3

I have a regex that I'm trying to use in Swift to parse out the color values of a string in the form of "rgba(255, 255, 255, 1)"

My regex string is this:

^rgba?\(\s*(\d{1,3}(?:\.\d+)?\%?)\s*,\s*(\d{1,3}(?:\.\d+)?\%?)\s*,\s*(\d{1,3}(?:\.\d+)?\%?)\s*(?:\s*,\s*(\d+(?:\.\d+)?)\s*)?\)$

You can see it working here:

cl.ly/XxuH

When I escape the backslashes and attempt to use it with NSRegularExpression it no longer matches the given string.

^rgba?\\(\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*(?:\\s*,\\s*(\\d+(?:\\.\\d+)?)\\s*)?\\)$

Is there something I am doing wrong?

Code Example:

import Foundation

var pattern = "^rgba?\\(\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*(?:\\s*,\\s*(\\d+(?:\\.\\d+)?)\\s*)?\\)$"

var string = "rgba(255, 234, 243, 1)"

var regex = NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions(0), error: nil)

regex.numberOfMatchesInString(string, options: nil, range: NSMakeRange(0, countElements(string))) // Yields 1. Should yield 4
Rob
  • 415,655
  • 72
  • 787
  • 1,044
erickreutz
  • 2,779
  • 3
  • 21
  • 18

1 Answers1

2

numberOfMatchesInString returns 1 because the entire pattern matches once. Use rangeAtIndex() to get the ranges matched by the capture groups:

let pattern = "^rgba?\\(\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*(?:\\s*,\\s*(\\d+(?:\\.\\d+)?)\\s*)?\\)$"
let regex = NSRegularExpression(pattern: pattern, options: nil, error: nil)

let rgba : NSString = "rgba(255, 234, 243, 1)"
if let match = regex!.firstMatchInString(rgba, options: nil, range: NSMakeRange(0, rgba.length)) {
    println(rgba.substringWithRange(match.rangeAtIndex(1)))
    println(rgba.substringWithRange(match.rangeAtIndex(2)))
    println(rgba.substringWithRange(match.rangeAtIndex(3)))
    println(rgba.substringWithRange(match.rangeAtIndex(4)))
}

Output:

255
234
243
1

Update: Using the Regex type that was introduced with Swift 5.7, requires macOS 13+ or iOS 16+):

let rgba = "rgba(255, 234, 243, 1)"

let pattern = /rgba?\(\s*(\d{1,3}(?:\.\d+)?\%?)\s*,\s*(\d{1,3}(?:\.\d+)?\%?)\s*,\s*(\d{1,3}(?:\.\d+)?\%?)\s*(?:\s*,\s*(\d+(?:\.\d+)?)\s*)?\)/

if let match = try? pattern.wholeMatch(in: rgba) {
    print(match.1)
    print(match.2)
    print(match.3)
    print(match.4)
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382