Reading Numbers from Strings
NSScanner *parser =7
[NSScanner scannerWithString: @"1 plus 2"];8 9
NSString *operation;11 12
[NSCharacterSet whitespaceCharacterSet]];14 15
[parser scanInt: operands];16
[parser scanInt: operands+1];
Two of the first things any C programmer learns to use are the printf() and scanf() functions. These are very, very similar—one is almost an inverse of the other—and they let you construct formatted strings and parse data from them. We've already seen that NSString has a rough analogue of sprintf(), so you can construct strings from format strings and variables, but what is the Objective-C equivalent of sscanf()? How, given a string, do we parse values from it?
The answer lies in the NSScanner class. This class is a very powerful tokenizer class. You create an instance of NSScanner attached to a string and then scan values from it, one at a time.
The messages you send to a scanner all have the same form. They take a pointer to a variable and return a BOOL, indicating whether they succeeded. The scanner stores the current scanning index in the string, and only increments it on a successful scan, so you can try parsing the next characters in different ways. You can also implement read-ahead and backtracking quite easily with NSScanner. If you send it a -scanLocation message, it returns the current index in the string. You can then try scanning a few things, get to an error, and backtrack by sending it a -setScanLocation: message, resetting the old index.
One of the most powerful methods in NSScanner is -scanCharactersFromSet:intoString:. This reads a string from the current scanning point until it encounters a character not present in the specified set. As we will see in Chapter 6, you can construct NSCharacterSet instances with any arbitrary set of characters, or you can use one of the standard ones.
The example at the start of this section reads a number, then a word, then another number from a string. The number is read using the built in -scanInt: method, but the word is a bit more complex. It uses an NSCharacterSet, in this case the set of all letters.
This isn't the only NSCharacterSet used in this example. This scanner is also configured to skip whitespace. The setCharactersToBeSkipped: message sent to the scanner tells it to ignore any characters in the set passed as the argument. Passing the whitespace character set tells it to skip any whitespace that occurs between calls. If there are characters in this set at the position where the scanner starts reading when you send it a scan message, it will skip past them. It will not skip these characters while parsing a token, so putting "1 2" in the string would be read as two separate numbers, not as 12.