Wednesday, April 25, 2012

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