Skip to content

Instantly share code, notes, and snippets.

@robtimp
Last active August 29, 2015 14:21
Show Gist options
  • Save robtimp/2544790985bb7ec12623 to your computer and use it in GitHub Desktop.
Save robtimp/2544790985bb7ec12623 to your computer and use it in GitHub Desktop.
String Parsing (objc.io #9) Swift version
// objc.io Issue #9
// February, 2014
// String Parsing by Chris Eidhof
//
// Swift version by Rob Hudson
import UIKit
// NSTextCheckingResult using NSRange, rather than Range<String.Index>, so we need an NSString, rather than a String
let string: NSString = "backgroundColor = #ff0000"
var error: NSError?
let pattern = "(\\w+) = #(\\p{Hex_Digit}{6})"
let expression = NSRegularExpression(pattern: pattern, options: nil, error: &error)
let result = expression?.firstMatchInString(string as String, options: nil, range: NSMakeRange(0, string.length))
if let result = result {
let key = string.substringWithRange(result.rangeAtIndex(1))
let value = string.substringWithRange(result.rangeAtIndex(2))
}
// objc.io Issue #9
// February, 2014
// String Parsing by Chris Eidhof
//
// Example 4
// Swift version by Rob Hudson
import UIKit
extension UIColor {
class func colorWithHexString(colorCode: String, alpha: Float = 1.0) -> UIColor {
var scanner = NSScanner(string:colorCode)
var color:UInt32 = 0;
scanner.scanHexInt(&color)
let mask = 0x000000FF
let r = CGFloat(Float(Int(color >> 16) & mask)/255.0)
let g = CGFloat(Float(Int(color >> 8) & mask)/255.0)
let b = CGFloat(Float(Int(color) & mask)/255.0)
return UIColor(red: r, green: g, blue: b, alpha: CGFloat(alpha))
}
}
let FormatError = 100
let MyErrorDomain = "io.objc.parsing"
let string = "backgroundColor = (189, 23, 95)\ntextColor = #179ac0"
var scanner: NSScanner!
func parse(string: String, inout error: NSError?) -> [String : UIColor]? {
scanner = NSScanner(string: string)
scanner.charactersToBeSkipped = NSCharacterSet.whitespaceCharacterSet()
var result = [String : UIColor]()
let letters = NSCharacterSet.letterCharacterSet()
while !scanner.atEnd {
var key: NSString?
var value: UIColor?
let didScan = scanner.scanCharactersFromSet(letters, intoString: &key)
scanner.scanString("=", intoString: nil)
scanColor(&value)
if let key = key as? String {
result[key] = value
}
scanner.scanCharactersFromSet(NSCharacterSet.newlineCharacterSet(), intoString: nil) // scan an optional newline
}
return result
}
func scanColor(inout color: UIColor?) -> Bool {
return scanHexColorIntoColor(&color) || scanTupleColorIntoColor(&color)
}
func scanHexColorIntoColor(inout color: UIColor?) -> Bool {
let hexCharacterSet = NSCharacterSet(charactersInString: "0123456789abcdefABCDEF")
var colorString: NSString?
if scanner.scanString("#", intoString: nil) &&
scanner.scanCharactersFromSet(hexCharacterSet, intoString: &colorString) &&
colorString?.length == 6 {
color = UIColor.colorWithHexString(colorString as! String)
return true
}
return false
}
func scanTupleColorIntoColor(inout color: UIColor?) -> Bool {
var red = 0, green = 0, blue = 0
let didScan = scanner.scanString("(", intoString: nil) &&
scanner.scanInteger(&red) &&
scanner.scanString(",", intoString: nil) &&
scanner.scanInteger(&green) &&
scanner.scanString(",", intoString: nil) &&
scanner.scanInteger(&blue) &&
scanner.scanString(")", intoString: nil)
if didScan {
color = UIColor(red: CGFloat(Double(red) / 255.0), green: CGFloat(Double(green) / 255.0), blue: CGFloat(Double(blue) / 255.0), alpha: 1.0)
return true
}
return false
}
var error: NSError?
parse(string, &error)
// objc.io Issue #9
// February, 2014
// String Parsing by Chris Eidhof
//
// Example 5
// Swift version by Rob Hudson
import UIKit
let string = "myView.left = otherView.right * 2 + 10\n" +
"viewController.view.centerX + myConstant <= self.view.centerX"
func tokenize(contents: String) -> [AnyObject] {
let scanner = NSScanner(string: contents)
var tokens = [AnyObject]()
while !scanner.atEnd {
for token in ["=", "+", "*", ">=", "<=", "."] {
if scanner.scanString(token, intoString: nil) {
tokens.append(token)
}
}
var result: NSString?
if scanner.scanCharactersFromSet(NSCharacterSet.letterCharacterSet(), intoString: &result) {
if let result = result as? String {
tokens.append(result)
}
}
var doubleResult = 0.0
if scanner.scanDouble(&doubleResult) {
tokens.append(doubleResult)
}
}
return tokens
}
let example = "myConstant = 100\n" +
"myView.left = otherView.right * 2 + 10\n" +
"viewController.view.centerX + myConstant <= self.view.centerX"
let result = tokenize(example)
let expected: [AnyObject] = ["myConstant", "=", 100, "myView", ".", "left", "=", "otherView", ".", "right", "*", 2, "+", 10, "viewController", ".", "view", ".", "centerX", "+", "myConstant", "<=", "self", ".", "view", ".", "centerX"]
// We can't compare AnyObject arrays with == or !=, so we'll use this function
func arraysAreEqual(array1: Array<AnyObject>, array2: Array<AnyObject>) -> Bool {
if array1.count != array2.count {
return false
}
for i in 0..<array1.count {
if let string1 = array1[i] as? String, string2 = array2[i] as? String {
if string1 != string2 {
return false
}
} else if let number1 = array1[i] as? NSNumber, number2 = array2[i] as? NSNumber {
if number1 != number2 {
return false
}
}
}
return true
}
arraysAreEqual(result, expected) // true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment