Pages

Sunday, July 18, 2010

Cocoa: NSScanner

sscanf is a standard C function. We use it so rarely, but it exists and can be the fastest method to parse a string. In order to remind I post this short program that uses sscanf to retrieve two float number from a string:
#include <stdio.h>

int main (int argc, const char * argv[])
{
float x, y;
const char* string = "3.1415 6.28";
sscanf(string, "%f %f", &x, &y);
printf("x = %.4f, y = %.2f\n", x, y);
return 0;
}

How to parse this string in Objective-C?
Firstly, this is Objective-C, so the same code will work:
#import <Foundation/Foundation.h>
#include <stdio.h>

int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

float x,y;
const char* string = "3.1415 6.28";
sscanf(string, "%f %f", &x, &y);

NSLog(@"x = %.4f, y = %.2f", x, y);

[pool drain];
return 0;
}
Secondly, this is Objectve-C. So there is a special class NSScanner that does the work.
#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

float x, y;
NSString* str = @"3.1415 6.28";
NSScanner* scanner = [NSScanner scannerWithString:str];
[scanner scanFloat: &x];
[scanner scanFloat: &y];
NSLog(@"x = %.4f, y = %.2f", x, y);
[pool drain];
return 0;
}

Let's make a more complicated example. The following program will create a text file and save three basic graphical structures in it: NSPoint, NSSize and NSRect.
#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

NSString* fileName = @"coordinate.txt";
NSError* err = nil;

NSPoint point;
NSSize size;
NSRect rect;

// Write NSPoint, NSSize and NSRect to file.
point = NSMakePoint( 3.1415, 6.28 );
size = NSMakeSize( 2, 14 );
rect = NSMakeRect( 10, 10, 200, 100 );

NSString* outString = [NSString 
stringWithFormat:@"point = %@; size = %@; rectangle = %@;",
      NSStringFromPoint(point), NSStringFromSize(size), NSStringFromRect(rect) ];

[outString writeToFile: fileName 
atomically: NO encoding: NSASCIIStringEncoding error: &err];

[pool drain];
return 0;
}
The output file looks so:

Of course, this file can be parsed in the standard C with the simple sscanf. The next Objective-C program does it with NSScanner class:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

NSString* fileName = @"coordinate.txt";
NSError* err = nil;

NSPoint point;
NSSize size;
NSRect rect;

NSStringEncoding encoding;
NSString* inString = [NSString stringWithContentsOfFile: fileName
usedEncoding: &encoding
error: &err];

NSString* strPoint = @"point =";
NSString* strSize = @"size =";
NSString* strRect = @"rectangle =";

if ( err == nil )
{
if ([inString length] > 0)
{
NSString* str;
NSScanner* scanner = [NSScanner scannerWithString: inString];

if ( [ scanner scanString: strPoint intoString: NULL] )
{
[scanner scanUpToString: @";" intoString: &str];
[scanner scanString: @";" intoString: NULL];
point = NSPointFromString( str );
}

if ( [scanner scanString: strSize intoString: NULL])
{
[scanner scanUpToString: @";" intoString: &str];
[scanner scanString: @";" intoString: NULL];
size = NSSizeFromString( str );
}

if ( [scanner scanString:strRect intoString: NULL] )
{
str = [inString substringFromIndex: [scanner scanLocation]];
rect = NSRectFromString( str );
}

NSLog( @"point = %@", NSStringFromPoint( point ) );
NSLog( @"size = %@", NSStringFromSize( size ) );
NSLog( @"rectangle = %@", NSStringFromRect( rect ) );
}
}

[pool drain];
return 0;
}
Program output:

Program loaded.
run
[Switching to process 57339]
Running…
2010-07-18 21:48:24.201 CoordinatesToString[57339:a0f] point = {3.1415, 6.28}
2010-07-18 21:48:24.205 CoordinatesToString[57339:a0f] size = {2, 14}
2010-07-18 21:48:24.206 CoordinatesToString[57339:a0f] rectangle = {{10, 10}, {200, 100}}

Mac OS X Reference Library:
NSScanner Class Reference
String Programming Guide. Scanners.

No comments:

Post a Comment