1

Let's assume I have a string ("G00 X0.0000 Y0.0000") and I need to to parse its contents. Here is my code:

NSCharacterSet *params = [NSCharacterSet characterSetWithCharactersInString:@"XY"];

//setup the scanner
NSScanner *scanner = [NSScanner scannerWithString:stringToBeScanned];
NSString *scanned = nil;

//scan the string
NSLog(@"%@", stringToBeScanned);
while ([scanner scanUpToCharactersFromSet:params intoString:&scanned]) {

    struct keypair code;
    code.key = [scanned characterAtIndex:0];
    code.value = [[scanned substringFromIndex:1] doubleValue];

    NSLog(@"--> %@ [%lu]= (%c, %.4f)", scanned, [scanner scanLocation], code.key, code.value);
}

And the output to NSLog:

G00 X0.0000 Y0.0000 
--> G00  [4]= (G, 0.0000)

My characterSet includes both 'X' and 'Y' and I can't figure out why my NSScanner won't scan in the 'X0.0000 ' - it should find that Y and pull in everything from X up to Y according to my understanding.

I can see from the scanLocation that the scanner is stopping at index 4 (correctly), but the loop either doesn't continue or evaluates to false. Shouldn't the scanner keep looping and finding my delimiters (from the characterSet) and grabbing data?

2 Answers2

0

scanUpToCharactersFromSet:intoString: scans up to the "X" and gives you the characters it scanned "G00 ".

Note that it does not scan the "X". When you call the method again, it looks at the next character (the "X"), notices that it is a character in the set, and stops scanning. As it scanned no characters, it then returns NO.

To scan the "X" (or "Y"), you will want to use scanCharactersFromSet:intoString: as well.

一二三
  • 21,059
  • 11
  • 65
  • 74
  • oh. you are saying that in order for it continue scanning that string and pass by the x (scanUpTo: "Y") -- i'd have to remove the "X" from the characterSet? hmm... there are a number of different characters I could encounter and need to take different actions based on which character I encounter (not just X and Y). Is there a different way you could suggest to do this? I was trying to make it as compact and efficient as possible. – donfmorrison Sep 12 '12 at 23:04
  • thanks for the info. using this information I have added my solution below. – donfmorrison Sep 13 '12 at 00:19
0

I solved this issue. Basically I receive a string with a list of "codes" followed by a value associated with that command/parameter. There could several different "commands" in each string, or none at all. The key was to use scanCharactersFromSet: and scanUpToCharactersFromSet: in order to capture the right pairings and parse the entire string while staying very flexible. It's a little ugly, I know.

Here is my code:

//setup the scanner
NSScanner *scanner = [NSScanner scannerWithString:[self stringByAppendingString:@"!"]];
NSCharacterSet *codeset = [NSCharacterSet characterSetWithCharactersInString:@"GMTFIJKPRSXYZ!"];
NSString *scanned = nil;
char codechar;

//perform the first scan
[scanner scanCharactersFromSet:codeset intoString:&scanned];
if (scanned)
    codechar = [scanned characterAtIndex:0];

//scan the string
while ([scanner scanUpToCharactersFromSet:codeset intoString:&scanned]) {
    struct keypair code;
    code.key = codechar;
    code.value = [scanned doubleValue];

    NSLog(@"--> (%c, %.4f)", code.key, code.value);

    //skip over the delimeter we encountered
    [scanner scanCharactersFromSet:codeset intoString:&scanned];
    if (scanned)
        codechar = [scanned characterAtIndex:0];

}