有没有办法获得NSRanges的NSArray在另一个NSString内部出现NSString?

时间:2010-09-05 18:41:19

标签: objective-c cocoa nsstring syntax-highlighting

我最近一直在为一个个人项目开发一个易于使用的语法高亮系统。到目前为止,通过查找特定字符串的范围并在NSTextView中突出显示该范围,我可以正常工作。一切都有效,直到您尝试两次输入突出显示的单词,这会导致下面显示的错误:

<div class="container">
    <div> <!-- This <div> would not get highlighted -->
        Hello World
    </div>
</div> <!-- this </div> would not get highlighted -->

我相信这是因为我只使用rangeOfString方法首次出现NSString,因此只突出显示第一个突出显示的项目。

很抱歉很长的解释!无论如何,我想知道是否有一个rangeOfString方法或类似的东西,可以在另一个NSString中为NSString的每次出现提供NSRanges的NSArray。下面是我目前使用的代码行:

NSString *textViewString = [textView string];
NSString *textToHighlight = @"<div>";
NSRange area;

area.location = 0;
area.length = [textViewString length];

NSRange range = [textViewString rangeOfString: textToHighlight 
                                      options: NSCaseInsensitiveSearch 
                                        range: area];

我想要的是这样的:

NSString *textViewString = [textView string];
NSString *textToHighlight = @"<div>";
NSRange area;

area.location = 0;
area.length = [textViewString length];

NSArray *ranges = [textViewString rangesOfString: textToHighlight
                                         options: NSCaseInsensitiveSearch
                                           range: area];

int i;
int total = [ranges count];
for (i = 0; i < total; i++) {
    NSRange occurrence = [ranges objectAtIndex: i];
    // Apply color highlighting here
}

如果这是不可能的,有人可以指出我正确的方向或建议另一种方法进行语法高亮?谢谢!

2 个答案:

答案 0 :(得分:3)

没有这样的方法。您可以使用rangeOfSubstring:options:range:来获取每个匹配,并随时缩小范围:在每次匹配后,您将搜索范围的位置更改为匹配范围(位置+长度)之后的字符,并缩小搜索范围差异的长度。


在现代的基于块的世界中,编写实现上述内容的an “enumerate substrings that match…” method并不难。这是看起来像:

- (NSUInteger) enumerateSubstringsMatchingString_PRH:(NSString *)stringToFind
    options:(NSStringCompareOptions)mask
    usingBlock:(void (^)(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop))block
{
    NSUInteger count = 0;

    NSUInteger selfLength = self.length;
    NSRange searchRange = { 0, selfLength };
    NSRange foundRange;
    BOOL stop = NO;
    while (( ! stop ) && (foundRange = [self rangeOfString:stringToFind options:mask range:searchRange]).location != NSNotFound) {
        ++count;
        if (block != NULL) {
            @autoreleasepool {
                NSString *substring = [self substringWithRange:foundRange];
                block(substring, foundRange, /*TODO include terminators and separators in enclosingRange as described in enumerateSubstringsWithOptions:: docs*/ foundRange, &stop);
            }
        }
        searchRange.location = NSMaxRange(foundRange);
        if (searchRange.location >= self.length)
            break;
        searchRange.length = selfLength - searchRange.location;
    }

    return count;
}

上面链接的Gist提供了一些明显的测试用例。

答案 1 :(得分:1)

NSRange不是对象,因此您需要将其放在一个对象中。查看NSValue +valueWithRange:类方法。