非正则表达式替代单词边界

时间:2013-10-10 21:11:27

标签: c# .net regex performance

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

虽然它比我已经拥有的速度快得多,但我还是不喜欢每个文件大约需要500毫秒的时间(在使用秒表的100x36k代币循环中定时)。

在移动我的标记的优先级之后,我已经将500ms切成两半并且通过向我的大多数标记添加“简单匹配”布尔值而获得额外的50ms(大致)(这基本上意味着它应该使用一个简单的string.Contains(Ordinal)而不是Regex.Match)。

为了获得最佳性能,我显然希望摆脱大多数(如果不是全部)Regex.Match次呼叫。为了实现这一点,我需要一些模拟正则表达式\b标签的东西,也就是所谓的单词边界(意思是它应该只匹配整个单词)。

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

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

1 个答案:

答案 0 :(得分:1)

我不确定为什么我最初的问题对我来说似乎很明显。我没有得到我的正则表达式修复,因为分析显示即使是最简单的正则表达式仍然需要比我想要的更多。它可能是一个穷人勒克斯,但我仍然希望它尽可能地表现。

然而,问题是.NET是否有内置词边界的替代方法,如果没有,我将如何在不使用正则表达式的情况下实现它。

第一个问题的答案似乎是

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

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

根据大多数Regex文档,这会模仿\w标记(忽略此方法!显然导致\W),作为回报用于\b,但没有在结果中匹配它。

然后我在一个像这样的方法中使用它:

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

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

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

此外,在以这种方式转换了所有我的正则表达式后,我从250毫秒变为仅仅50毫秒的完全相同的文件。 Lexing拥有的所有110个脚本文件总共不到一秒钟,平均每个文件大约7ms。