как создать "вложенный сплит" сортов - PullRequest
0 голосов
/ 12 июля 2010

Кажется, это должно быть довольно просто, но по какой-то причине я не могу придумать правильный способ сделать это:

У меня есть строка h, которая выглядит как one(two(three four) five six) seven.

Я бы хотел разделить это на массив хэшей, чтобы результат был примерно таким:

{'one' => 
       {'two' => 
              {'three' => nil, 'four' => nil},
        'five'=>nil, 'six'=>nil
       }, 'seven'=>nil}

. Можно предположить, что круглые скобки равны.1011 * Есть ли простой способ сделать это?На языке, который поощряет использование внешности, это было бы относительно просто;Я не думаю, что использую Ruby достаточно долго, чтобы понять, как Ruby решает подобные проблемы.

Спасибо!

Ответы [ 3 ]

1 голос
/ 12 июля 2010

Вот рекурсивное решение:

def f(str)
  parts = ['']
  nesting_level = 0
  str.split('').each do |c|
    if c != ' ' or nesting_level > 0
      parts.last << c
    end
    if [' ', ')'].include?(c) and nesting_level == 0
      parts << ''
    end
    case c
    when '('
      nesting_level += 1
    when ')'
      nesting_level -= 1
    end
  end
  hash = {}
  parts.each do |seg|
    unless seg.include?('(')
      hash[seg] = nil
    else
      key = seg[/^[^\(\) ]+/]
      value = seg[(key.length + 1)..(seg.length - 2)].to_s
      hash[key] = f value
    end
  end
  hash
end

f 'one(two(three four) five six) seven' #=> {"one"=>{"two"=>{"three"=>nil, "four"=>nil}, "five"=>nil, "six"=>nil}, "seven"=>nil}
1 голос
/ 12 июля 2010

Без контекста трудно дать вам что-нибудь, что могло бы работать в более общем случае.

Этот код будет работать для вашего конкретного примера, просто используя регулярные выражения и eval, но я не хотел бы использовать подобный код на практике.

Для более сложного анализа строк вы можете использовать http://treetop.rubyforge.org/ или аналогичный. Но тогда вы попадаете на территорию написания собственного языка.

h = "one(two(three four) five six) seven"

s = h.tr "()", "{}"
s = "{#{s}}"
s = s.gsub /(\w+)/, '"\1" =>'
s = s.gsub /\>\s\"+/, '> nil, "'
s = s.gsub /\>\}+/, '> nil },'
s = s[0..-2]

puts h
r = eval(s)
puts r.inspect
puts r.class.name

Был ли какой-то конкретный пример, на который вы пытались получить ответ?

Кроме того, я мог бы добавить, что вы можете значительно упростить свою жизнь, если сможете предоставить строки, которые более естественным образом соответствуют анализу Ruby. Очевидно, это зависит от того, имеете ли вы контроль над источником.

0 голосов
/ 31 июля 2010

Использование вложенных групп регулярных выражений. Не такой производительный, как синтаксический анализатор / сканер, поскольку он будет повторно сканировать подгруппы во время рекурсивного вызова.

def hash_from_group(str)
    ret = {}
    str.scan(/
        (?<key_name>\w+)
        (?<paren_subgroup>
            \(
                (?:
                    [^()]
                    |
                    \g<paren_subgroup>
                )*  # * or + here, depending on whether empty parens are allowed, e.g. foo(bar())
            \)
        )? # paren_subgroup optional
    /x) do
        md = $~
        key,value = md[:key_name], md[:paren_subgroup]
        ret[key] = value ? hash_from_group(value) : nil
    end
    ret
end


p hash_from_group('one(two(three four) five six) seven') # => {"one"=>{"two"=>{"three"=>nil, "four"=>nil}, "five"=>nil, "six"=>nil}, "seven"=>nil}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...