問題は、コレクションを反復処理しているときにコレクションを変更していることです。これはおそらく機能しません。(そして私の意見では、そうすべきではありません。この場合、Rubyは、誤った動作を黙って許可するのではなく、例外を発生させる必要があります。これは、他のほとんどすべての命令型言語が行うことです。)
これは、元のスタイルを維持しながら、私が思いつくことができる最高のものです。
require 'pp'
data = %w[start before rgb 255 255 255 hex FFFFFF after end]
rgb_count = hex_count = 0
rgb, hex, rest = data.reduce([[], [], []]) do |acc, el|
acc.tap do |rgb, hex, rest|
next (rgb_count = 3 ; rgb << el) if /rgb/i =~ el
next (rgb_count -= 1 ; rgb << el) if rgb_count > 0
next (hex_count = 1 ; hex << el) if /hex/i =~ el
next (hex_count -= 1 ; hex << el) if hex_count > 0
rest << el
end
end
data.replace(rest)
pp rgb, hex, data
# ["rgb", "255", "255", "255"]
# ["hex", "FFFFFF"]
# ["start", "before", "after", "end"]
しかし、あなたが抱えているのは構文解析の問題であり、それは実際にはパーサーによって解決されるべきです。単純な手巻きのパーサー/ステートマシンは、おそらく上記よりも少しコードが多くなりますが、はるかに読みやすくなります。
これがあなたの問題を解決する単純な再帰下降パーサーです:
class ColorParser
def initialize(input)
@input = input.dup
@rgb, @hex, @data = [], [], []
end
def parse
parse_element until @input.empty?
return @rgb, @hex, @data
end
private
def parse_element
parse_color or parse_stop_word
end
def parse_color
parse_rgb or parse_hex
end
def parse_rgb
return unless /rgb/i =~ peek
@rgb << consume
parse_rgb_values
end
再帰下降パーサーは、その構造が文法とほぼ完全に一致しているため、非常に気に入っています。入力が空になるまで要素を解析し続けるだけです。要素とは何ですか?さて、それは色の仕様またはストップワードです。色の仕様とは何ですか?ええと、それはRGBカラー仕様か16進カラー仕様のどちらかです。RGBカラー仕様とは何ですか?まあ、それは正規表現と/rgb/i
それに続くRGB値に一致するものです。RGB値とは何ですか?ええと、それはたった3つの数字です…
def parse_rgb_values
3.times do @rgb << consume.to_i end
end
def parse_hex
return unless /hex/i =~ peek
@hex << consume
parse_hex_value
end
def parse_hex_value
@hex << consume.to_i(16)
end
def parse_stop_word
@data << consume unless /rgb|hex/i =~ peek
end
def consume
@input.slice!(0)
end
def peek
@input.first
end
end
そのようにそれを使用してください:
data = %w[start before rgb 255 255 255 hex FFFFFF after end]
rgb, hex, rest = ColorParser.new(data).parse
require 'pp'
pp rgb, hex, rest
# ["rgb", 255, 255, 255]
# ["hex", 16777215]
# ["start", "before", "after", "end"]
比較のために、文法は次のとおりです。
- S →要素
*
- 要素→カラー
|
ワード
- 色→ rgbhex
|
_
- rgb → rgb rgbvalues
- rgbvalues →トークン トークン トークン
- hex → hex hexvalue
- hexvalue →トークン
- 単語→トークン