20

私はかなり単純な正規表現を持っていますが、名前付き正規表現を使用してそれをよりクリーンにし、結果を反復処理したいと考えていました。

テスト文字列:

testing_string = "111x222b333"

私の正規表現:

regexp = %r{
                (?<width> [0-9]{3} ) {0}
                (?<height> [0-9]{3} ) {0}
                (?<depth> [0-9]+ ) {0}

                \g<width>x\g<height>b\g<depth>
            }x
dimensions = regexp.match(testing_string)

これは魅力のように機能しますが、ここで問題が発生します。

dimensions.each { |k, v| dimensions[k] = my_operation(v) }

# ERROR !

 undefined method `each' for #<MatchData "111x222b333" width:"111" height:"222" depth:"333">.

ありません。eachMatchData オブジェクトのメソッドであり、モンキー パッチを適用したくありません。

この問題を解決するにはどうすればよいですか?

思ったほど明確ではありませんでした。要点は、名前とハッシュのような構造を維持することです。

4

5 に答える 5

38

完全なハッシュが必要な場合:

captures = Hash[ dimensions.names.zip( dimensions.captures ) ]
p captures
#=> {"width"=>"111", "height"=>"222", "depth"=>"333"}

名前と値のペアを反復処理するだけの場合:

dimensions.names.each do |name|
  value = dimensions[name]
  puts "%6s -> %s" % [ name, value ]
end
#=>  width -> 111
#=> height -> 222
#=>  depth -> 333

代替案:

dimensions.names.zip( dimensions.captures ).each do |name,value|
  # ...
end

[ dimensions.names, dimensions.captures ].transpose.each do |name,value|
  # ...
end

dimensions.names.each.with_index do |name,i|
  value = dimensions.captures[i]
  # ...
end
于 2012-07-27T15:06:42.240 に答える
1

すべてのキャプチャに一意の名前が付いている場合、 @ Phrogz の答えは正しいですが、複数のキャプチャに同じ名前を付けることが許可されています。正規表現のドキュメントの例を次に示します。

このコードは、名前が重複するキャプチャをサポートしています。

captures = Hash[
  dimensions.regexp.named_captures.map do |name, indexes|
    [
      name,
      indexes.map { |i| dimensions.captures[i - 1] }
    ]
  end
]

# Iterate over the captures
captures.each do |name, values|
  # name is a String
  # values is an Array of Strings
end
于 2015-11-20T23:19:03.730 に答える
1

ハッシュを作成するという問題全体を少し違った方法で攻撃します。

irb(main):052:0> testing_string = "111x222b333"
"111x222b333"
irb(main):053:0> hash = Hash[%w[width height depth].zip(testing_string.scan(/\d+/))]
{
    "width" => "111",
    "height" => "222",
    "depth" => "333"
}

正規表現は強力ですが、そのサイレンコールは魅力的すぎる可能性があり、何かを達成するためのより単純な、または直接的な方法がある場合、正規表現を使用しようとすることに夢中になります. それはちょうど考えるべきことです。


OPのコメントに従って、スキャンされた要素の数を追跡するには:

hash = Hash[%w[width height depth].zip(scan_result = testing_string.scan(/\d+/))]
=> {"width"=>"111", "height"=>"222", "depth"=>"333"}
scan_result.size
=> 3

hash.sizeキーなどを含む配列のサイズと同様に、それも返します。

于 2012-07-27T16:22:40.610 に答える
-1

名前を保持したい場合は、次のことができます

new_dimensions = {}
dimensions.names.each { |k| new_dimensions[k] = my_operation(dimensions[k]) }
于 2012-07-27T13:41:33.287 に答える