我正在研究一个 ruby 基础词法分析器。为了提高性能,我将所有标记的正则表达式加入到一个带有匹配组名称的大正则表达式中。生成的正则表达式如下所示:
/\A(?<__anonymous_-1038694222803470993>(?-mix:\n+))|\A(?<__anonymous_-1394418499721420065>(?-mix:\/\/[\A\n]*))|\A(?<__anonymous_3077187815313752157>(?-mix:include\s+"[\A"]+"))|\A(?<LET>(?-mix:let\s))|\A(?<IN>(?-mix:in\s))|\A(?<CLASS>(?-mix:class\s))|\A(?<DEF>(?-mix:def\s))|\A(?<DEFM>(?-mix:defm\s))|\A(?<MULTICLASS>(?-mix:multiclass\s))|\A(?<FUNCNAME>(?-mix:![a-zA-Z_][a-zA-Z0-9_]*))|\A(?<ID>(?-mix:[a-zA-Z_][a-zA-Z0-9_]*))|\A(?<STRING>(?-mix:"[\A"]*"))|\A(?<NUMBER>(?-mix:[0-9]+))/
我将它与我的字符串匹配,生成一个 MatchData,其中只解析了一个标记:
bigregex =~ "\n ... garbage"
puts $~.inspect
哪个输出
#<MatchData
"\n"
__anonymous_-1038694222803470993:"\n"
__anonymous_-1394418499721420065:nil
__anonymous_3077187815313752157:nil
LET:nil
IN:nil
CLASS:nil
DEF:nil
DEFM:nil
MULTICLASS:nil
FUNCNAME:nil
ID:nil
STRING:nil
NUMBER:nil>
因此,正则表达式实际上匹配了 "\n" 部分。现在,我需要确定它所属的匹配组(从#inspect 输出中可以清楚地看到它是_匿名-1038694222803470993,但我需要以编程方式获取它)。
除了迭代#names之外,我找不到任何选项:
m.names.each do |n|
if m[n]
type = n.to_sym
resolved_type = (n.start_with?('__anonymous_') ? nil : type)
val = m[n]
break
end
end
它验证匹配组确实有匹配项。
这里的问题是它很慢(我在循环中花费了大约 10% 的时间;还有 8% 的时间@input[@pos..-1]
用来确保\A按预期工作以匹配字符串的开头(我不丢弃输入,只需移动 @pos在里面)。
您可以在GH repo查看完整代码。
关于如何使它至少更快一点的任何想法?是否有任何选项可以更轻松地计算“成功”匹配组?