使用NSScanner解析字符串

时间:2011-03-22 18:35:07

标签: objective-c ios nsstring nsscanner

我有一个带有格式标签的字符串,例如There are {adults} adults, and {children} children。我有一个字典,其中“成人”和“孩子”作为键,我需要查找值并用该值替换宏。这是完全动态的;键可以是任何东西(所以我不能硬编码stringByReplacingString)。

在过去,我之前通过循环遍历可变字符串并搜索字符来完成类似的事情;在我去的时候从源字符串中删除我已经搜索过的内容。看起来这正是NSScanner的设计类型,所以我尝试了这个:

NSScanner *scanner = [NSScanner scannerWithString:format];
NSString *foundString;
scanner.charactersToBeSkipped = nil;

NSMutableString *formatedResponse = [NSMutableString string];

while ([scanner scanUpToString:@"{" intoString:&foundString]) {
    [formatedResponse appendString:[foundString stringByReplacingOccurrencesOfString:@"{" withString:@""]]; //Formatted string contains everything up to the {

    [scanner scanUpToString:@"}" intoString:&foundString];

    NSString *key = [foundString stringByReplacingOccurrencesOfString:@"}" withString:@""];

    [formatedResponse appendString:[data objectForKey:key]];

}

NSRange range = [format rangeOfString:@"}" options:NSBackwardsSearch];

if (range.location != NSNotFound) {
    [formatedResponse appendString:[format substringFromIndex:range.location + 1]];
}

问题在于,当我的字符串以“{”开头时,扫描仪返回NO,而不是YES。 (这是文档所说的应该发生的事情)。我是否滥用NSScanner? scanUpToString不包括作为其输出的一部分被搜索的字符串这一事实似乎使它几乎无用......

可以轻松更改以执行我想要的操作,还是需要使用可变字符串重新编写并手动搜索字符?

1 个答案:

答案 0 :(得分:12)

使用isAtEnd确定何时停止。此外,{}不包含在scanUpToString:的结果中,因此它们将位于下一个字符串的开头,但是循环之后的追加不是必需的,因为即使找不到搜索字符串,扫描仪也会返回扫描内容。

// Prevent scanner from ignoring whitespace between formats. For example, without this, "{a} {b}" and "{a}{b}" and "{a}     
//{b}" are all equivalent
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@""]];
while(![scanner isAtEnd]) {
    if([scanner scanUpToString:@"{" intoString:&foundString]) {
        [formattedResponse appendString:foundString];
    }
    if(![scanner isAtEnd]) {
        [scanner scanString:@"{" intoString:nil];
        foundString = @""; // scanUpToString doesn't modify foundString if no characters are scanned
        [scanner scanUpToString:@"}" intoString:&foundString];
        [formattedResponse appendString:[data objectForKey:foundString];
        [scanner scanString:@"}"];
    }
}