有效地在大型NSString中找到许多关键字中的第一个

时间:2011-11-18 09:24:58

标签: objective-c regex string performance cocoa

我需要找到大NSString中的所有关键字(对于解析源代码),而我当前的实现速度太慢,但我不确定如何改进它。

我正在使用NSRegularExpression,基于它比我能编写的任何内容更优化的假设,但性能比我预期的要慢。有谁知道更快的实现方法?

目标字符串将包含utf-8字符,但关键字本身将始终为纯字母数字ascii。我想这可以用来优化一些东西吗?

@implementation MyClass

// i'm storing the regular expression in a static variable, since it never changes and I need to re-use it often
static NSRegularExpression *keywordsExpression;

+ (void)initialize
{
  [super initialize];

  NSArray *keywords = [NSArray arrayWithObjects:@"accumsan", @"adipiscing", @"aliquam", @"aliquet", @"amet", @"ante", @"arcu", @"at", @"commodo", @"congue", @"consectetur", @"consequat", @"convallis", @"cras", @"curabitur", @"cursus", @"dapibus", @"diam", @"dolor", @"dui", @"elit", @"enim", @"erat", @"eros", @"est", @"et", @"eu", @"felis", @"fermentum", @"gravida", @"iaculis", @"id", @"imperdiet", @"integer", @"ipsum", @"lacinia", @"lectus", @"leo", nil];

  NSString *pattern = [NSString stringWithFormat:@"\\b(%@)\\b", [keywords componentsJoinedByString:@"|"]; // \b(accumsan|adipiscing|aliquam|…)\b
  keywordsExpression = [NSRegularExpression regularExpressionWithPattern:pattern] options:NSRegularExpressionCaseInsensitive error:NULL];
}

// this method will be called in quick succession, I need it to be a able to run tens
// of thousands of times per second. The target string is big (50KB or so), but the
// search range is short, rarely more than 30 characters
- (NSRange)findNextKeyword:(NSString *)string inRange:(NSRange)range
{
  return [keywordsExpression rangeOfFirstMatchInString:string options:0 range:range];
}

@end

编辑 根据@ CodeBrickie的回答,我已经更新了我的代码,对整个字符串执行一次正则表达式搜索,并将匹配保存到缓存的{{ 1}},然后每次调用该方法时,它会在NSIndexSet中搜索关键字范围,而不是搜索字符串。结果大约快了一个数量级:

NSIndexSet

这似乎运作良好,并且性能达到我想要的范围。在接受这个建议之前,我想再等一会儿,看看是否还有更多的建议。

3 个答案:

答案 0 :(得分:3)

由于您需要关键字及其范围,我会使用enumerateMatchesInString:options:range:usingBlock:并实现一个块,该关键字将关键字添加为关键字,将范围添加为NSMutableDictionary的值。

因此,在调用之后,您只需要调用整个字符串以及字典中包含范围的所有关键字。

答案 1 :(得分:1)

我建议您使用非常基本的正则表达式匹配任何单词,然后在包含关键字的词典中查找匹配的单词,而不是组合正则表达式以匹配所有关键字;如果这个词不存在,请忽略它继续前进。

您可以根据您对关键字的了解来定制正则表达式,以实现最高效率。例如,如果您知道您只查找三到十二个小写ASCII字母的单词,则可以使用@"\\b[a-z]{3,12}+\\b"。与你的怪物正则表达式相比,它有许多替代品。

我在自己的语法高亮显示项目中使用了这项技术并取得了巨大成功。这是在Java中,但快速查看NSRegularExpression文档会产生一个非常相似的功能集。

答案 2 :(得分:0)

如果将搜索切换到某些NSLiteral搜索而不是不区分大小写,会发生什么?

当然,你需要不区分大小写,但如果速度更快,它会给你提供想法。

最大速度会有更多的工作,涉及较低的c字符串和strstr(),我敢打赌。