提问



首先,我正在编写一个iOS 5应用程序。举个例子,假设我有以下字符串:


100 - PARK STREET / JAMES PLACE


我想以最有效(和代码优雅)的方式从这个字符串中提取两个道路名称。我已经尝试过使用[string componentsSeparatedByString...]等的组合,但这很快就会变得非常混乱。此外,它需要大量的条件语句来处理如下情况:


100 - BI-CENTENNIAL DRIVE / JAMES PLACE


因为它包含一个嵌套的连字符,如果我们使用[string componentsSeparatedByString:@"-"]并需要重新组装,它将被拆分。


在某些情况下,字符串可能具有略微不同的格式,例如:


100- BI-CENTENNIAL DRIVE / JAMES PLACE


(数字和连字符之间没有空格)


100-BI-CENTENNIAL DRIVE /JAMES PLACE


(根本没有任何空格,加上斜线和第二道路名称之间没有空格)


但是,我们总是可以假设字符串中只有一个斜杠,用于分隔两个道路名称。


道路名称​​也应该被剥去任何前导和尾随空格。


我认为使用NSScanner可以更有效和更优雅的方式完成整个过程,但不幸的是,我没有必要的经验来使这个课程有效。任何建议都将非常感激。

最佳参考


你也可以使用正则表达式。[17]


请注意,在块中我使用捕获块,通过[result rangeAtIndex:i]

索引1现在将是门牌号,索引2将返回第一条街道,3则返回第二条街道。[18]


#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{

    @autoreleasepool {
        NSArray *streets = [NSArray arrayWithObjects:@"100 - PARK STREET / JAMES PLACE", @"100 - BI-CENTENNIAL DRIVE / JAMES PLACE", @"100- BI-CENTENNIAL DRIVE / JAMES PLACE", @"100-BI-CENTENNIAL DRIVE /JAMES PLACE", nil];

        NSString *text = [streets componentsJoinedByString:@" "];
        NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(\\d+) {0,1}- {0,1}(\\D+) *\\/ *(\\D+)" options:NSRegularExpressionCaseInsensitive error:nil];

        [regex enumerateMatchesInString:text options:0 
                                  range:NSMakeRange(0, [text length]) 
                             usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) 
        {
            for (int i = 1; i< [result numberOfRanges] ; i++) {
                NSLog(@"%@", [text substringWithRange:[result rangeAtIndex:i]]);
            }
        }];
    }
    return 0;
}


输出:


100
PARK STREET 
JAMES PLACE 
100
BI-CENTENNIAL DRIVE 
JAMES PLACE 
100
BI-CENTENNIAL DRIVE 
JAMES PLACE 
100
BI-CENTENNIAL DRIVE 
JAMES PLACE


编辑以回复评论


int main (int argc, const char * argv[])
{

    @autoreleasepool {
        NSArray *streets = [NSArray arrayWithObjects:@"100 - PARK STREET / JAMES PLACE", @"100 - BI-CENTENNIAL DRIVE / JAMES PLACE", @"100- BI-CENTENNIAL DRIVE / JAMES PLACE", @"100-BI-CENTENNIAL DRIVE /JAMES PLACE",@"100 - PARK STREET", nil];

        NSRegularExpression *regex1 = [NSRegularExpression regularExpressionWithPattern:@"(\\d+) *- *([^\\/]+) *$" options:NSRegularExpressionCaseInsensitive error:nil];
        NSRegularExpression *regex2 = [NSRegularExpression regularExpressionWithPattern:@"(\\d+) *- *([^\\/]+) *\\/ *([^\\/]+) *$" options:NSRegularExpressionCaseInsensitive error:nil];
        for (NSString *text in streets) {                        
            NSRegularExpression *regex = ([regex1 numberOfMatchesInString:text options:NSRegularExpressionCaseInsensitive range:NSMakeRange(0, [text length])]) ? regex1 : regex2;
            [regex enumerateMatchesInString:text options:0 
                                      range:NSMakeRange(0, [text length]) 
                                 usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) 
             {
                 for (int i = 1; i< [result numberOfRanges] ; i++) {
                     NSLog(@"%@", [text substringWithRange:[result rangeAtIndex:i]]);
                 }

             }];
        }
    }
    return 0;
}


第二次修改


int main (int argc, const char * argv[])
{

    @autoreleasepool {
        NSArray *streets = [NSArray arrayWithObjects:   @"100 - PARK STREET / JAMES PLACE", 
                                                        @"100 - BI-CENTENNIAL DRIVE / JAMES PLACE", 
                                                        @"100- BI-CENTENNIAL DRIVE / JAMES PLACE", 
                                                        @"100-BI-CENTENNIAL DRIVE /JAMES PLACE",
                                                        @"100 - PARK STREET",
                                                        @"100 - PARK STREET / ",
                                                        @"100 - PARK STREET/ ",
                                                        @"100 - PARK STREET/",
                            nil];

        NSRegularExpression *regex1 = [NSRegularExpression regularExpressionWithPattern:@"(\\d+) *- *([^\\/]+) *$" options:NSRegularExpressionCaseInsensitive error:nil];
        NSRegularExpression *regex2 = [NSRegularExpression regularExpressionWithPattern:@"(\\d+) *- *([^\\/]+) *\\/ *([^\\/]*) *$" options:NSRegularExpressionCaseInsensitive error:nil];
        for (NSString *text in streets) { 

            text= [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
            NSLog(@"\n>%@<", text);
            NSRegularExpression *regex = ([regex1 numberOfMatchesInString:text options:NSRegularExpressionCaseInsensitive range:NSMakeRange(0, [text length])]) ? regex1 : regex2;
            [regex enumerateMatchesInString:text options:0 
                                      range:NSMakeRange(0, [text length]) 
                                 usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) 
             {
                 for (int i = 1; i< [result numberOfRanges] ; i++) {
                     NSLog(@"%@", [text substringWithRange:[result rangeAtIndex:i]]);
                 }

             }];
        }
    }
    return 0;
}

其它参考1


只是在我的浏览器中编码:


NSString* line = @"100- BI-CENTENNIAL DRIVE / JAMES PLACE";
NSScanner* scanner = [NSScanner scannerWithString:line];
NSString* number;
if (![scanner scanUpToString:@"-" intoString:&number])
    /* handle parse failure */;
NSString* firstRoad;
if (![scanner scanUpToString:@"/" intoString:&firstRoad])
    /* handle parse failure */;
NSString* secondRoad = [str substringFromIndex:[scanner scanLocation]];


从结果字符串中可能会有额外的空格进行修剪。

其它参考2


这看起来像是NSRegularExpression的工作。[19]


我认为是R.E.就像是


^[0-9]+ *- *(.*)$


会匹配你想要的。

其它参考3


这是使用这个可怕的小 NSScanner 类的另一个例子。


假设您有一个包含四个值的字符串,并希望将它们转换为CGRect:


NSString* stringToParse = @"10, 20, 600, 150";             
CGRect rect = [self stringToCGRect:stringToParse];

NSLog(@"Rectangle: %.0f, %.0f, %.0f, %.0f", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);


要做到这一点,你要写一个讨厌的小函数,如下所示:


-(CGRect)stringToCGRect:(NSString*)stringToParse
{
    NSLog(@"Parsing the string: %@", stringToParse);
    int x, y, wid, hei;

    NSString *subString;
    NSScanner *scanner = [NSScanner scannerWithString:stringToParse];
    [scanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:nil];
    [scanner scanCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:&subString];
    x = [subString integerValue];

    [scanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:nil];
    [scanner scanCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:&subString];
    y = [subString integerValue];

    [scanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:nil];
    [scanner scanCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:&subString];
    wid = [subString integerValue];

    [scanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:nil];
    [scanner scanCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:&subString];
    hei = [subString integerValue];

    CGRect rect = CGRectMake(x, y, wid, hei);
    return rect;
}


请原谅我的消极情绪,但我很累,晚上10点30分,我鄙视必须编写这样的Objective-C代码,完全了解使用过去15年的任何Microsoft开发环境,这将是采取一行代码。


GRRRR ....