views:

472

answers:

5

I am writing a front-end for a command line utility in Objective-C (Cocoa). I need to parse the output to check for different types of messages. There are two basic types; information messages and download status messages. Information messages always begin with one of the following: INFO:, WARNING:, ERROR:, or : . The download status messages look like the following: 60.56MB / 237.03MB 1526kbps 25.5%, 00:15:47 remaining

I need to detect which of the two types of messages a string is and if it is a download status message, parse out the percentage and speed. If it is an information message, I will simply append it to the log. I know I will need an NSScanner to parse out the components. What I really can't figure out is how to check if it is a download status message. The first three types of information messages are fairly easy to detect but the fourth type I am unsure on as well.

Any help would be greatly appreciated.

Thanks, Thomas

A: 

Objective C is a full standard C too, and standard C provides sscanf etc

Will
+2  A: 

RegexKitLite. Documentation Download 3.1

johne
A: 

As someone else said, if possible link to the underlying library instead of parsing the output of the cli tool. If that is not an option, I don't see why you cannot simply try and parse the progress message, and if that fails simply fall back to try one of the other messages.

+1  A: 

NSScanner can do the job.

Write a function that creates a scanner and attempts to scan all the values, units, and intermediate parts (such as the slash at one point and the comma later on). If it succeeds on all of them, return the values and possibly the units by reference, and return YES. If it fails to scan anything, return NO.

Then, call that function. If it returns YES, it is a status line, and the variables whose addresses you passed to the function now contain the values. If it returns NO, it isn't a status line (or your scanning code missed a case).

Peter Hosey
A: 

Ended up using a scanner as Peter Hosey suggested. Here is my solution:

     if ([output hasPrefix:@"INFO:"] || [output hasPrefix:@"WARNING:"] || [output hasPrefix:@"ERROR:"] || 
  [output hasSuffix:@"default"] || [output hasPrefix:[show pid]])
 {
  //Add Status Message to Log
  [self addToLog:output noTag:YES];

  if ([output hasPrefix:@"ERROR: Failed to"])
  {
   [self addToLog:@"Download Failed" noTag:NO];
   NSLog(@"Download Failed");
  }
 }
 else
 {
  //Process Status Message
  [self addToLog:output noTag:YES];
  NSScanner *scanner = [NSScanner scannerWithString:output];
  NSDecimal recieved, total, percentage;
  NSInteger speed=0;
  NSString *timeRemaining;
  if(![scanner scanDecimal:&recieved]) recieved = [[NSNumber numberWithInt:0]decimalValue];
  [scanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] 
        intoString:nil];
  if(![scanner scanDecimal:&total]) total = [[NSNumber numberWithInt:0]decimalValue];
  [scanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] 
        intoString:nil];
  if(![scanner scanInteger:&speed]) speed = [[NSNumber numberWithInt:0]integerValue];
  [scanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] 
        intoString:nil];
  if(![scanner scanDecimal:&percentage]) percentage = [[NSNumber numberWithInt:0]decimalValue];
  [scanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] 
        intoString:nil];
  [scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"a"] 
        intoString:&timeRemaining];