2011-08-25 119 views
7

我有一個搜索字符串,人們可以使用引號將短語分組在一起,並將其與單個關鍵字混合使用。例如,像這樣的字符串:將NSString分隔成NSArray,但允許引號將單詞分組

"Something amazing" rooster 

我想的是分離成一個NSArray,使得其將具有Something amazing(沒有引號)爲一個元件,並且rooster作爲其他。

componentsSeparatedByStringcomponentsSeparatedByCharactersInSet都不符合法案。有沒有簡單的方法來做到這一點,或者我應該自己編寫代碼?

+0

你可能有一些運氣NSRegularExpression,雖然想出了一個可靠的單組對於這項任務可能是不可能的。 :-)另一種方法可能是在空間上分割(@「」),然後檢查每個單詞尋找以引號開頭或結尾的單詞,並將這些單詞合併成單個短語。 –

回答

1

我結束了一個正則表達式,因爲我已經在使用RegexKitLite,並且創建了這個NSString + SearchExtensions類。

.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 

這將返回與搜索字符串字符串的一個NSArray,消除圍繞短語雙引號。

+0

謝謝,蒂姆。簡單,像魅力一樣工作。你需要放棄新的iOS版本的'autorelease',但它確實很酷。並且比其他Tim的「DIY」回答更有幫助:) – mgarciaisaia

2

你可能不得不自己編寫一些代碼,但是NSScanner應該是一個很好的基礎。如果您使用scanUpToCharactersInSet方法查找所有直到您的下一個空格或引用字符的內容,都可以選中關鍵字。一旦遇到相當的字符,您可以繼續使用字符集中的引號結束掃描,以便引號內的空格不會導致標記結束。

+0

如果對此答案感到難過,請參閱OP的答案[此處](http://stackoverflow.com/a/7379286/641451)以及一個可行的解決方案。 – mgarciaisaia

0

我會跑-componentsSeparatedByString:@"\""第一,然後創建一個BOOL isPartOfQuote,初始化爲YES如果字符串的第一個字符是」,否則設置爲NO

然後創建一個可變數組返回: NSMutableArray* masterArray = [[NSMutableArray alloc] init];

然後,創建一個循環在陣列從分離返回:

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

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

然後從函數返回masterArray

1

如果您允許稍微不同的方法,您可以嘗試Dave DeLong's CHCSVParser。它旨在解析CSV字符串,但是如果將空格字符設置爲分隔符,我相當確定您將獲得預期的行爲。

或者,您可以查看代碼並查看它如何處理帶引號的字段 - 它是在MIT許可下發布的。

+3

+1由於明顯的原因 –

+0

@DaveDeLong,它確實花了我一些時間才找到「明顯的原因」:P –

1

我做了一個簡單的方法來做到這一點使用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; 

}

此方法將數組轉換回代碼字符串,再引述多字的標籤:

+ (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; 

}