Separating NSString into NSArray, but allowing quotes to group words

一笑奈何 提交于 2019-12-10 03:56:25

问题


I have a search string, where people can use quotes to group phrases together, and mix this with individual keywords. For example, a string like this:

"Something amazing" rooster

I'd like to separate that into an NSArray, so that it would have Something amazing (without quotes) as one element, and rooster as the other.

Neither componentsSeparatedByString nor componentsSeparatedByCharactersInSet seem to fit the bill. Is there an easy way to do this, or should I just code it up myself?


回答1:


You probably will have to code some of this up yourself, but the NSScanner should be a good basis on which to build. If you use the scanUpToCharactersInSet method to look for everything up to your next whitespace or quote character to can pick off words. Once you encounter a quite character, you could continue to scan using just the quote in the character set to end at, so that spaces within the quotes don't result in the end of a token.




回答2:


I made a simple way to do this using NSScanner:

+ (NSArray *)arrayFromTagString:(NSString *)string {

NSScanner *scanner = [NSScanner scannerWithString:string];
NSString *substring;
NSMutableArray *array = [[NSMutableArray alloc] init];

while (scanner.scanLocation < string.length) {

    // test if the first character is a quote
    unichar character = [string characterAtIndex:scanner.scanLocation];
    if (character == '"') {
        // skip the first quote and scan everything up to the next quote into a substring
        [scanner setScanLocation:(scanner.scanLocation + 1)];
        [scanner scanUpToString:@"\"" intoString:&substring];
        [scanner setScanLocation:(scanner.scanLocation + 1)];  // skip the second quote too
    }
    else {
        // scan everything up to the next space into the substring
        [scanner scanUpToString:@" " intoString:&substring];
    }
    // add the substring to the array
    [array addObject:substring];

    //if not at the end, skip the space character before continuing the loop
    if (scanner.scanLocation < string.length) [scanner setScanLocation:(scanner.scanLocation + 1)];
}
return array.copy;

}

This method will convert the array back to a tag string, re-quoting the multi-word tags:

+ (NSString *)tagStringFromArray:(NSArray *)array {

NSMutableString *string = [[NSMutableString alloc] init];
NSRange range;

for (NSString *substring in array) {
    if (string.length > 0) {
        [string appendString:@" "];
    }
    range = [substring rangeOfString:@" "];
    if (range.location != NSNotFound) {
        [string appendFormat:@"\"%@\"", substring];
    }
    else [string appendString:substring];
}
return string.description;

}




回答3:


I ended up going with a regular expression as I was already using RegexKitLite, and creating this NSString+SearchExtensions category.

.h:

//  NSString+SearchExtensions.h
#import <Foundation/Foundation.h>
@interface NSString (SearchExtensions)
-(NSArray *)searchParts;
@end

.m:

//  NSString+SearchExtensions.m
#import "NSString+SearchExtensions.h"
#import "RegexKitLite.h"

@implementation NSString (SearchExtensions)

-(NSArray *)searchParts {
    __block NSMutableArray *items = [[NSMutableArray alloc] initWithCapacity:5];

    [self enumerateStringsMatchedByRegex:@"\\w+|\"[\\w\\s]*\"" usingBlock: ^(NSInteger captureCount,
       NSString * const capturedStrings[captureCount],
       const NSRange capturedRanges[captureCount],
       volatile BOOL * const stop) {

        NSString *result = [capturedStrings[0] stringByReplacingOccurrencesOfRegex:@"\"" withString:@""];

        NSLog(@"Match: '%@'", result);
        [items addObject:result];
    }];        
    return [items autorelease];
}
@end

This returns an NSArray of strings with the search strings, removing the double quotes that surround the phrases.




回答4:


If you'll allow a slightly different approach, you could try Dave DeLong's CHCSVParser. It is intended to parse CSV strings, but if you set the space character as the delimiter, I am pretty sure you will get the intended behavior.

Alternatively, you can peek into the code and see how it handles quoted fields - it is published under the MIT license.




回答5:


I would run -componentsSeparatedByString:@"\"" first, then create a BOOL isPartOfQuote, initialized to YES if the first character of the string was a ", but otherwise set to NO.

Then create a mutable array to return: NSMutableArray* masterArray = [[NSMutableArray alloc] init];

Then, create a loop over the array returned from the separation:

for(NSString* substring in firstSplitArray) {
    NSArray* secondSplit;
    if (isPartOfQuote == NO) {
        secondSplit = [substring componentsSeparatedByString:@" "];
    }
    else {
        secondSplit = [NSArray arrayWithObject: substring];
    }

    [masterArray addObjectsFromArray: secondSplit];
    isPartOfQuote = !isPartOfQuote;
}

Then return masterArray from the function.



来源:https://stackoverflow.com/questions/7193427/separating-nsstring-into-nsarray-but-allowing-quotes-to-group-words

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!