假设我有字符串
"[1,2,[3,4,[5,6]],7]"
我如何将其解析为数组
[1,2,[3,4,[5,6]],7]
在我的使用案例中,嵌套结构和模式完全是任意的。
我目前的临时解决方案是在每个时段之后添加一个空格并使用YAML.load
,但如果可能的话,我希望有一个更干净的空间。
(如果可能的话,不需要外部库)
答案 0 :(得分:40)
使用JSON
正确解析该特定示例:
s = "[1,2,[3,4,[5,6]],7]"
#=> "[1,2,[3,4,[5,6]],7]"
require 'json'
#=> true
JSON.parse s
#=> [1, 2, [3, 4, [5, 6]], 7]
如果这不起作用,您可以尝试通过eval
运行字符串,但必须确保没有传递实际的ruby代码,因为eval
可以用作注入漏洞。
编辑:这是一个简单的递归,基于正则表达式的解析器,没有验证,没有经过测试,没有用于生产用途等:
def my_scan s
res = []
s.scan(/((\d+)|(\[(.+)\]))/) do |match|
if match[1]
res << match[1].to_i
elsif match[3]
res << my_scan(match[3])
end
end
res
end
s = "[1,2,[3,4,[5,6]],7]"
p my_scan(s).first #=> [1, 2, [3, 4, [5, 6]], 7]
答案 1 :(得分:14)
使用Ruby标准库YAML
可以完成同样的操作,如下所示:
require 'yaml'
s = "[1,2,[3,4,[5,6]],7]"
YAML.load(s)
# => [1, 2, [3, 4, [5, 6]], 7]
答案 2 :(得分:4)
&#34;显然&#34;最好的解决方案是编写自己的解析器。 [如果你喜欢编写解析器,以前从未这样做过,想要学习新的东西,或者想要控制精确的语法]
require 'parslet'
class Parser < Parslet::Parser
rule(:space) { str(' ') }
rule(:space?) { space.repeat(0) }
rule(:openbrace_) { str('[').as(:op) >> space? }
rule(:closebrace_) { str(']').as(:cl) >> space? }
rule(:comma_) { str(',') >> space? }
rule(:integer) { match['0-9'].repeat(1).as(:int) }
rule(:value) { (array | integer) >> space? }
rule(:list) { value >> ( comma_ >> value ).repeat(0) }
rule(:array) { (openbrace_ >> list.maybe.as(:list) >> closebrace_ ).as(:arr)}
rule(:nest) { space? >> array.maybe }
root(:nest)
end
class MyTransform < Parslet::Transform
rule(:int => simple(:x)) { Integer(x) }
rule(:op => '[', :cl => ']') { [] }
rule(:op => '[', :list => subtree(:x), :cl => ']') { Array(x) }
rule(:arr => subtree(:x)) { x }
end
def parse(s)
MyTransform.new.apply(Parser.new.parse(s))
end
parse " [ 1 , 2 , [ 3 , 4 , [ 5 , 6 , [ ]] ] , 7 ] "
答案 3 :(得分:0)
使用eval
array = eval("[1,2,[3,4,[5,6]],7]")