【问题标题】:Non-regex alternative to word boundaries单词边界的非正则表达式替代
【发布时间】:2013-10-10 21:11:26
【问题描述】:

我目前正在使用正则表达式编写词法分析器,如本文所述:Poor man's "lexer" for C#

虽然它比我已经拥有的要快得多,但我只是不喜欢每个文件仍然需要大约 500 毫秒(使用秒表在 100x36k 令牌的循环中计时)。

在移动我的令牌的优先级之后,我已经将 500 毫秒减少了一半,并且通过向我的大多数令牌添加一个“简单匹配”布尔值(这基本上意味着它应该使用一个简单的string.Contains(Ordinal) 而不是 Regex.Match)。

为了获得最佳性能,我显然想摆脱大部分(如果不是全部)Regex.Match 调用。为此,我需要在正则表达式中模拟 \b 标记的东西,也称为单词边界(意味着它应该只匹配整个单词)。

虽然我可以写一个简单的方法来检查我的“简单匹配”之前和之后的字符是否是非单词字符,但我想知道 .NET 是否有这个内置的东西?

如果我最终不得不编写自己的方法,最好的方法是什么?在我的单词之后选择字符的索引并检查它的字节值是否低于任何值?任何有关这方面的提示也将受到欢迎!

【问题讨论】:

  • 请注意,\b 仅当您的单词由字母、数字和下划线组成时才匹配单词边界。对于所有其他情况,它是无用的。
  • 我知道,但感谢您的提醒!只要我模拟\b 的确切行为,我的词法分析器就会产生我期望的确切输出。
  • 你在预编译你的正则表达式吗?这可以加快正则表达式匹配。此外,this question 可能会提供一些关于为什么您的正则表达式可能需要更长的处理时间的见解。不看你的表情很难知道。
  • 我正在使用正则表达式进行解析并获得比这更好的性能。我第二你是在预编译正则表达式吗?
  • Compiled 标志对性能的影响绝对为零。正如我在问题中描述的那样,我继续实施了\b 替代方案。只剩下 4 个表达式,我怀疑 CompileToAssembly 会为我带来很多性能,因为我已经下降到 120 毫秒(从原来的 500 毫秒)。

标签: c# .net regex performance


【解决方案1】:

不知道为什么我最初的问题被否决了,对我来说这似乎很清楚。我不是在修复我的正则表达式后,因为分析表明即使是最简单的正则表达式仍然比我想要的要多。它可能是一个糟糕的人词法分析器,但我仍然希望它尽可能地发挥最佳性能。

然而,问题是 .NET 是否有内置词边界的替代方案,如果没有,我将如何在不使用 Regex 的情况下自己实现它。

第一个问题的答案似乎是

至于第二个,我为char类写了一个扩展方法:

public static bool IsWordCharacter(this char character)
{
    return (
        (character >= 'a' && character <= 'z') || 
        (character >= 'A' && character <= 'Z') || 
        (character >= '0' && character <= '9') || 
        character == '_');
}

根据大多数正则表达式文档,这模仿了\w 标志(用! 否定此方法显然会导致\W),作为回报在\b 中使用,但在结果中没有匹配它。

然后我在类似这样的方法中使用它:

return 
    text.StartsWith(<needle>, StringComparison.Ordinal) 
    && !text[<length of needle>].IsWordCharacter()
        ? <length of needle> 
        : 0;

之后我的底层代码知道它是否必须使用或删除令牌。

免责声明:我知道这不是\b 的完整实现,但它符合我的目的。

此外,在以这种方式转换了我所有的 Regex' 之后,对于完全相同的文件,我从 250 毫秒缩短到了 50 毫秒。对我拥有的所有 110 个脚本文件进行词法分析总共需要不到一秒钟的时间,平均每个文件大约 7 毫秒。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-07
    • 2011-04-14
    • 2011-03-28
    • 1970-01-01
    • 2012-09-24
    • 1970-01-01
    相关资源
    最近更新 更多