Simple string parsing in Cocoa / Objective-C: parsing a command line into command and arguments
Asked Answered
S

4

3

Here's a piece of code to take a string (either NSString or NSAttributedString) input that represents a command line and parse it into two strings, the command cmd and the arguments args:

NSString* cmd = [[input mutableCopy] autorelease];
NSString* args = [[input mutableCopy] autorelease];
NSScanner* scanner = [NSScanner scannerWithString:[input string]];
[scanner scanUpToCharactersFromSet:[NSCharacterSet 
                                    whitespaceAndNewlineCharacterSet] 
                        intoString:&cmd];
if (![scanner scanUpToString:@"magicstring666" intoString:&args]) args = @"";

That seems to work but the magic string is a pretty absurd hack. Also, I'm not at all sure I'm doing things right with the autoreleases.

ADDED: The solution should also be robust to initial whitespace. Also, I originally had the input string called both input and inStr. Sorry for that confusion.

ADDED: I believe one thing the above code gets right that the answers so far don't is that args should not have any initial whitespace.

Skvorak answered 7/1, 2009 at 21:47 Comment(0)
B
10
NSString *cmd;
NSScanner *scanner = [NSScanner scannerWithString:[inStr string]];
[scanner scanUpToCharactersFromSet:[NSCharacterSet
                                    whitespaceAndNewlineCharacterSet] 
                        intoString:&cmd];
NSString *args = [[scanner string] substringFromIndex:[scanner scanLocation]];

Your autoreleases were OK, but allocating strings in the first place was unnecessary since NSScanner returns a new string by reference. Since NSScanner's charactersToBeSkipped include whitespace by default, it shouldn't get tripped up by initial whitespace.

Bahaism answered 7/1, 2009 at 22:39 Comment(0)
P
5

Something like this?

int index = [input rangeOfString:@" "].location;
NSString *cmd = [input substringToIndex:index]);
NSString *args = [input substringFromIndex:index + 1]);
Pulliam answered 7/1, 2009 at 21:58 Comment(1)
Sweet! I knew it should be very simple. Thanks! I guess both of our solutions are not robust to initial whitespace though, eh? Is there a simple "trim" function? Also, in your solution, no new memory is alloc'd, correct?Skvorak
I
3

The autoreleases you mentioned don't actually make any sense, all you're doing is creating a mutable copy (NSMutableString *) that's properly autoreleased, but since you're casting it to an NSString * there's no practical difference then just saying cmd = input;. Even that's not needed for args though, since NSScanner will overwrite what's there anyway.

The rangeOfString: would work, if you want to go this route you can trim leading whitespaces using NSString's stringByTrimmingCharactersInSet method (I would also test to be sure both arguments and the command exist, or you'll get an error). What I would do though, is use the NSString componentsSeparatedByCharactersInSet: method. This will give you an NSArray object containing the command and each argument in a separate index.

Interminable answered 7/1, 2009 at 23:40 Comment(1)
But that fails with arguments that have spaces in them - like shell commands looking like this: find . -name "my name"Somnifacient
S
1

If you want to expand the string into a full array of arguments like the input to 'main', you can use wordexp.

#import <wordexp.h>

+ (NSMutableArray*) splitArgumentString:(NSString*)strArgs
{
    wordexp_t expandedArgs;
    NSMutableArray *argArray = [NSMutableArray array];

    if(strArgs != nil && 0 == wordexp([strArgs UTF8String], &expandedArgs, 0))
    {
        for(size_t i = 0; i < expandedArgs.we_wordc; ++i)
        {
            NSString arg = [NSString stringWithCString:expandedArgs.we_wordv[i] encoding:NSUTF8StringEncoding];
            [argArray addObject:arg];
        }
        wordfree(&expandedArgs);
    }
    return argArray;        
}
Sclerosed answered 20/12, 2013 at 20:1 Comment(2)
is wordexp available part of MacOS SDK ? where is it? what is it? This Is awesome, and the thing I've been looking for a long time, only I didn't know this C API exists. Will it also be smart about args in quotes and double-quotes where they have spaces in them, and so on - like in shell commands?Somnifacient
It's been a long time since I worked on the platform. There are some docs here though: developer.apple.com/library/archive/documentation/System/…Sclerosed

© 2022 - 2024 — McMap. All rights reserved.