这看起来应该相当简单,但出于某种原因,我想不出正确的方法:
我的字符串h
看起来像one(two(three four) five six) seven
。
我想将其拆分为一个哈希数组,以便输出类似于
{'one' =>
{'two' =>
{'three' => nil, 'four' => nil},
'five'=>nil, 'six'=>nil
}, 'seven'=>nil}
我们可以假设括号数量相等。
有没有简单的方法可以做到这一点?在一种鼓励使用外观的语言中,这将是相对简单的;我不认为我已经使用Ruby足够长的时间来感受Ruby做这种问题的方式了。
谢谢!
答案 0 :(得分: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的字符串,你可以让你的生活更轻松。显然这取决于你是否掌握了来源。
答案 1 :(得分: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}
答案 2 :(得分: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}