我目前正在使用正则表达式编写词法分析器,如本文所述:Poor man's "lexer" for C#
虽然它比我已经拥有的速度快得多,但我还是不喜欢每个文件大约需要500毫秒的时间(在使用秒表的100x36k代币循环中定时)。
在移动我的标记的优先级之后,我已经将500ms切成两半并且通过向我的大多数标记添加“简单匹配”布尔值而获得额外的50ms(大致)(这基本上意味着它应该使用一个简单的string.Contains(Ordinal)
而不是Regex.Match
)。
为了获得最佳性能,我显然希望摆脱大多数(如果不是全部)Regex.Match
次呼叫。为了实现这一点,我需要一些模拟正则表达式\b
标签的东西,也就是所谓的单词边界(意思是它应该只匹配整个单词)。
虽然我可以疯狂地编写一个简单的方法来检查我的“简单匹配”之前和之后的字符是否是非单词字符,但我想知道.NET是否会有内置的东西?
如果我最终必须编写自己的方法,那么最好的方法是什么?在我的单词之后选择字符的索引并检查它的字节值是否低于任何值?有关这方面的任何提示也欢迎!
答案 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。