获取NSString中所有大写字母的NSRange对象数组的最快方法?

Bam*_*a91 4 iphone objective-c nsstring ios nsrange

我需要NSRange对象作为给定NSString中每个大写字母的位置,以输入自定义属性字符串类的方法. 

当然有很多方法可以实现这一点,例如rangeOfString:options:使用NSRegularExpressionSearch或使用RegexKitLite在遍历字符串时单独获取每个匹配. 

完成此任务的最快表现方法是什么?

Lil*_*ard 13

最简单的方法可能是使用-rangeOfCharacterFromSet:options:range:[NSCharacterSet uppercaseLetterCharacterSet].通过修改每次调用搜索的范围,您可以非常轻松地找到所有大写字母.类似下面的内容将为您提供所有范围的NSArray(编码为NSValues):

- (NSArray *)rangesOfUppercaseLettersInString:(NSString *)str {
    NSCharacterSet *cs = [NSCharacterSet uppercaseLetterCharacterSet];
    NSMutableArray *results = [NSMutableArray array];
    NSRange searchRange = NSMakeRange(0, [str length]);
    NSRange range;
    while ((range = [str rangeOfCharacterFromSet:cs options:0 range:searchRange]).location != NSNotFound) {
        [results addObject:[NSValue valueWithRange:range]];
        searchRange = NSMakeRange(NSMaxRange(range), [str length] - NSMaxRange(range));
    }
    return results;
}
Run Code Online (Sandbox Code Playgroud)

请注意,这不会将相邻范围合并为单个范围,但这很容易添加.

这是基于NSScanner的替代解决方案:

- (NSArray *)rangesOfUppercaseLettersInString:(NSString *)str {
    NSCharacterSet *cs = [NSCharacterSet uppercaseLetterCharacterSet];
    NSMutableArray *results = [NSMutableArray array];
    NSScanner *scanner = [NSScanner scannerWithString:str];
    while (![scanner isAtEnd]) {
        [scanner scanUpToCharactersFromSet:cs intoString:NULL]; // skip non-uppercase characters
        NSString *temp;
        NSUInteger location = [scanner scanLocation];
        if ([scanner scanCharactersFromSet:cs intoString:&temp]) {
            // found one (or more) uppercase characters
            NSRange range = NSMakeRange(location, [temp length]);
            [results addObject:[NSValue valueWithRange:range]];
        }
    }
    return results;
}
Run Code Online (Sandbox Code Playgroud)

与上一个不同,这个将相邻的大写字符合并为一个范围.

编辑:如果你正在寻找绝对速度,这个可能是这里提出的3中最快的,同时仍然保持正确的unicode支持(注意,我还没有尝试编译这个):

// returns a pointer to an array of NSRanges, and fills in count with the number of ranges
// the buffer is autoreleased
- (NSRange *)rangesOfUppercaseLettersInString:(NSString *)string count:(NSUInteger *)count {
    NSMutableData *data = [NSMutableData data];
    NSUInteger numRanges = 0;
    NSUInteger length = [string length];
    unichar *buffer = malloc(sizeof(unichar) * length);
    [string getCharacters:buffer range:NSMakeRange(0, length)];
    NSCharacterSet *cs = [NSCharacterSet uppercaseLetterCharacterSet];
    NSRange range = {NSNotFound, 0};
    for (NSUInteger i = 0; i < length; i++) {
        if ([cs characterIsMember:buffer[i]]) {
            if (range.location == NSNotFound) {
                range = (NSRange){i, 0};
            }
            range.length++;
        } else if (range.location != NSNotFound) {
            [data appendBytes:&range length:sizeof(range)];
            numRanges++;
            range = (NSRange){NSNotFound, 0};
        }
    }
    if (range.location != NSNotFound) {
        [data appendBytes:&range length:sizeof(range)];
        numRanges++;
    }
    if (count) *count = numRanges;
    return [data bytes];
}
Run Code Online (Sandbox Code Playgroud)