An NSScanner is instantiated with a String and once instantiated it can be searched. This searching occurs via a stepping through of the string. For example, let's suppose we have the following string, "Swift 1.2", and want to set up a scan for the letters in this string:
// first we create an NSScanner instance let scanner = NSScanner(string: "Swift 1.2") // then we create a string into which the scan will output var str:NSString? // finally we perform the scan scanner.scanCharactersFromSet(NSCharacterSet.letterCharacterSet(), intoString: &str) // true // and here we have the result str // "Swift"
Moving on
But suppose we ran the same scan again:scanner.scanCharactersFromSet(NSCharacterSet.letterCharacterSet(), intoString: &str) // false scanner.string // "Swift 1.2"This time the result is false, not because the string has changed or been consumed but because the scanner has moved forwards, as we see when we examine the .scanLocation.
scanner.scanLocation // 5And simply reseting or changing the scanLocation enables us to find the same string again.
scanner.scanLocation = 0 scanner.scanCharactersFromSet(NSCharacterSet.letterCharacterSet(), intoString: &str) // true
Double or nothing
The scanner can seek more than just strings containing characters from a set, it can also look for Doubles, Floats, Integers and so on:var num = Double() scanner.scanDouble(&num) // true num // 1.2However, let's reset to the original scanLocation and see how it fares then:
scanner.scanLocation = 0 scanner.scanDouble(&num) // false
Ignorance is bliss
You'll see that scanDouble now returns false, this is because as soon as a scanner doesn't match what it is looking for it stops. So if there's a letter before the number, it won't find the number. This is unless we ignore certain characters.var num = Double() scanner.scanLocation = 0 let skipCharacters = NSMutableCharacterSet() skipCharacters.formUnionWithCharacterSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) skipCharacters.formUnionWithCharacterSet(NSCharacterSet.letterCharacterSet()) scanner.charactersToBeSkipped = skipCharacters scanner.scanDouble(&num) num // 1.2The default is to skip whitespace and newline characters, and in order to change this we need to set the skipCharacters property.
I thank NSHipster here for a post on NSScanner for providing information on how to combine NSCharacterSets using formUnionWithCharacterSet().
Up to no good
If you don't know what you are looking for, but instead know what you are not looking for, you can search up to the characters that are not wanted instead:scanner.charactersToBeSkipped = nil scanner.scanLocation = 0 scanner.scanUpToCharactersFromSet(NSCharacterSet.decimalDigitCharacterSet(), intoString: &str) str // "Swift "And you'll notice here that the white space at the end of the string is included when we search up to the first number, because the charactersToBeSkipped property was set to nil.
Conclusion
Aside from NSCharacterSet and NSScanner being Cocoa classes, you'll notice that the scanner's intoString must, at the time of writing, be an NSString and not a String. But apart from this NSScanner behaves nicely with Swift.
Comments
Post a Comment