0

私はルビーバーサーレクサーに取り組んでいます。パフォーマンスを向上させるために、すべてのトークンの正規表現を、一致グループ名を持つ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リポジトリで完全なコードを確認できます。

それを少なくとも少し速くする方法についてのアイデアはありますか?「成功した」マッチグループを簡単に把握するオプションはありますか?

4

2 に答える 2

1

私はこれを完全に誤解したかもしれませんが、1つのトークンを除いてすべてがそうではないnilと思います、そしてそれはあなたの後のものですか?

その場合、使用している正規表現のフレーバーに応じて、負の先読みを使用して値以外のnil値をチェックできます。

([^\n:]+:(?!nil)[^\n\>]+)

これはトークン全体と一致しますNAME:value

于 2012-11-19T13:00:29.870 に答える
1

regexp メソッド.captures()とを使用してこれを行うことができ.names()ます。

matching_string = "\n ...garbage"   # or whatever this really is in your code
@input = matching_string.match bigregex   # bigregex = your regex
arr = @input.captures

arr.each_with_index do |value, index|     
  if not value.nil?
    the_name_you_want = @input.names[index]
  end
end

または、複数の成功した値が予想される場合は、次のようにすることができます。

success_names_arr = []
success_names_arr.push(@input.names[index]) #within the above loop

元のアイデアとかなり似ていますが、効率的な方法を探している場合は、それが.captures()役立つはずです。

于 2012-11-19T13:59:26.857 に答える