私はルビーバーサーレクサーに取り組んでいます。パフォーマンスを向上させるために、すべてのトークンの正規表現を、一致グループ名を持つ1つの大きな正規表現に結合しました。結果の正規表現は次のようになります。
/\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]+))/
これを文字列と照合して、1つのトークンが解析される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%の時間を費やします。また、 \ A@input[@pos..-1]
が文字列の先頭と一致するように期待どおりに機能することを確認するために8%を取得します(入力を破棄せず、@posをシフトするだけです)初期化)。
GHリポジトリで完全なコードを確認できます。
それを少なくとも少し速くする方法についてのアイデアはありますか?「成功した」マッチグループを簡単に把握するオプションはありますか?