Самый простой способ, вероятно, использовать -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;
}
Обратите внимание, что это не объединит смежные диапазоны в один диапазон, но добавить его достаточно просто.
Вот альтернативное решение на основе 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;
}
В отличие от последнего, он объединяет смежные заглавные буквы в один диапазон.
Редактировать : Если вы ищете абсолютную скорость, эта, вероятно, будет самой быстрой из 3 представленных здесь, сохраняя при этом правильную поддержку юникода (обратите внимание, я не пробовал компилировать это):
// 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];
}