2010-07-12 43 views
0

的“嵌套分”这似乎是它应该是相当简单的,但由于某些原因,我不能想这样做的正确方法:如何创建各种

我有一个字符串h看起来像one(two(three four) five six) seven

我想拆分此成哈希值的阵列,使得输出是一样的东西

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

我们可以假设,有括号的数量相等。

有没有简单的方法来做到这一点?在鼓励使用外表的语言中,这将是相对简单的;我不认为我已经使用Ruby足够长的时间来感受Ruby的这种做法。

谢谢!

回答

1

这里是一个递归解决方案:

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

没有任何上下文,很难给你任何可能在更一般情况下工作的东西。

这段代码适用于您的具体示例,只是使用正则表达式和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

使用嵌套的正则表达式的基团。不像分析器/扫描器那样高性能,因为这将在递归调用期间重新扫描子组。

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}