【问题标题】:How to speed up iPhone regular expressions with NSRegularExpression?如何使用 NSRegularExpression 加速 iPhone 正则表达式?
【发布时间】:2011-07-06 08:30:31
【问题描述】:

我的 iphone 应用程序使用正则表达式(使用 NSRegularExpression)对大量字符串(1000 多个)执行计算。这当然需要很多时间。有哪些加速正则表达式的策略?我研究过使用块,但我认为它不会有任何好处——它们似乎主要代表 lambda 功能(即,相当于 lisp)并在具有多个内核的 Mac 上使用。显然,现在的 iPhone 没有多核。

这是我的代码:

NSString *replaceRegexPattern = @"([\\(|\\[].*?[\\)|\\]])|(^to )";
NSRegularExpression *replaceRegex = [[NSRegularExpression regularExpressionWithPattern:replaceRegexPattern
                                                                              options:NSRegularExpressionCaseInsensitive
                                                                               error:nil] retain];
NSArray *myArray = <some data>;
NSString *myString, *compareValue;
for (i = 0; i < [myArray count]; i++) {
    myString = [myArray objectAtIndex:i];
    compareValue = [replaceRegex stringByReplacingMatchesInString:myString
                                                          options:0
                                                            range:NSMakeRange(0, [myString length])
                                                     withTemplate:@""];
    // do things with compareValue

}

为了回答下面的问题,我在这段代码中的目标是删除我的字符串中的任何文本,这些文本要么用括号括起来,要么以“to”开头。下面是一些例子:

  • 你好(再见)-->你好
  • 你好(再见 [n])-->你好
  • 说-->说
  • 说 (pf) --> 说

【问题讨论】:

  • 你的表达方式无所谓地删除了“to”、“TO”、“tO”和“To”。如果您只关心一种情况,您可以通过删除选项NSRegularExpressionCaseInsensitive 来加快速度。

标签: iphone regex ios optimization


【解决方案1】:

加快该正则表达式的最佳方法是使用所有格量词:

NSString *replaceRegexPattern = 
    @"^to\\s++|\\[[^\\[\\]]*+\\]|\\([^()]*+\\)";

如果由于左括号与正确的右括号不匹配而无法匹配,*+ 可以防止我们知道毫无意义的回溯。但是成功的匹配尝试也更有效率,因为正则表达式引擎不必保存使回溯成为可能的状态信息。

正如 Tim 所指出的,这不会匹配同种括号的嵌套实例,例如 ((foo))[[bar]]。它匹配匹配括号内任意数量的方括号,反之亦然。它不需要正确配对这些内括号,因此它将匹配(foo[)[(bar))],例如。你原来的正则表达式也是如此。

在字符类中包含 方括号可防止像 [[foo]((bar) 这样的不平衡匹配。

【讨论】:

    【解决方案2】:

    您确定正则表达式是解决此问题的正确工具吗?

    如果您想要做的只是删除括号内的文本,那么通过字符串的一个简单的逐字符循环就可以很容易地做到这一点,甚至可以正确处理嵌套的括号。

    在伪代码中:

     nesting_level = 0;
     while more_chars {
           c = next_char;
           if c == '(' or c == '[') 
               ++nesting_level;
           else if c == ')' or c == ']'
               --nesting_level;   // check for nesting_level < 0 here?
           else if nesting_level == 0
               result += c;
     }
    

    显然,做你自己的基准测试,但你可能会通过避免使用正则表达式来获得更好的性能。

    (如果您关心检测诸如“(hello]”之类的格式错误的内容,则可以为此添加简单的递归下降)

    【讨论】:

      【解决方案3】:

      由于我不知道您到底想做什么,因此很难给出有根据的建议,但看起来您的正则表达式可以改进一点。

      您真的要匹配(foo)[bar]|baz| 之类的字符串吗?您不需要在字符类中使用 | 交流发电机,因此除非您想匹配此处的第三个示例,否则请删除 |s。

      那么,既然你期待像(foo [bar] baz)这样的字符串,你需要把两种括号分开,你也可以加快你的正则表达式:

      @"^to |\\([^)]*\\)|\\[[^\\]]*\\]"
      

      这首先在字符串的开头检查to,然后寻找一个左括号/括号,除了右括号/括号之外的任何内容,以及一个右括号/括号。这需要更少的回溯,因此可能会更快一些。

      您将无法使用单个正则表达式处理相同类型 ((foo (bar) baz)) 的嵌套括号/括号,因为这不再是常规的 -​​ 除非您多次运行正则表达式替换操作,每个嵌套级别一次.因此,如果您运行 regex replace 两次,上述示例将被删除。

      【讨论】:

      • 感谢您的建议。我希望能够匹配嵌套的括号,但这不是最重要的方面。
      • 也可以这样吗? (foo (bar) baz)?因为这个(任意嵌套)不再是正则语言,不能被正常的正则表达式匹配。
      • 对。我想出的正则表达式是:\([^\)]*(\[[^\]]*\])?[^\)]*\)|\[[^\]]*\],匹配(foo)[bar](foo [bar] baz)
      • 我提出的解决方案有什么问题?它将匹配相同的字符串。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-31
      • 1970-01-01
      • 2012-03-05
      • 2012-03-24
      • 2015-10-03
      相关资源
      最近更新 更多