我正在为第三方API编写客户端,他们以奇怪的格式提供数据。起初,它可能看起来像JSON,但它不是,我对我应该如何处理它有点困惑。
这是一种基于键值的格式(很像JSON)。
这种格式可能是什么?我应该使用premade gem来解析它,还是应该构建我自己的解析器?
{ "anArray" = (
"100",
"200",
"300"
);
"aDictionary" = {
"aString" = "Something";
};
}
EDIT 这种格式似乎是Apple的属性列表,但它不是XML也不是Binary ......这有意义,因为API来自WebObjects Web服务。我将尝试使用CFPropertyList gem来解析它,如果有更好的解决方案,请告诉我。
编辑2 这是NextSTEP Property List。
答案 0 :(得分:1)
这是一个非常快速和肮脏的黑客攻击,它将语法转换为有效的Ruby,然后进行篡改。请注意,此可能是危险的。更重要的是,这会将键和值内的所有括号转换为方括号。
def parse(str)
eval(
str
.gsub( /" = (?=[({"])/, '" => ' ) # Dictionary separators become =>
.gsub( /(?<=[)}"]); (?=[)}"])/, ', ' ) # Dictionary semicolons become ,
.tr( '()', '[]' ) # ALL parens become square brackets
)
end
p parse('{ "anArray" = ( "100", "200", "300" ); "aDictionary" = { "aString" = "Something"; }; }')
#=> {"anArray"=>["100", "200", "300"], "aDictionary"=>{"aString"=>"Something"}}
答案 1 :(得分:1)
使用基于StringScanner的自定义解析器,这是一个强大的答案。它允许空格是可选的,允许在列表中的最后一项之后使用尾随逗号,并允许在最后一个字典键/值对之后省略分号。它允许最外面的项目是字典,数组或字符串。它允许任何类型的合法字符串内容,包括parens和花括号以及\n
等转义文本。
见过:
p parse('{ "array" = ( "1", "2", ( "3", "4" ) ); "hash"={ "key"={ "more"="oh}]yes;!"; }; }; }')
#=> {"array"=>["1", "2", ["3", "4"]], "hash"=>{"key"=>{"more"=>"oh}]yes;!"}}}
puts parse('("Escaped \"Quotes\" Allowed", "And Unicode \u2623 OK")')
#=> Escaped "Quotes" Allowed
#=> And Unicode ☣ OK
代码:
require 'strscan'
def parse(str)
ss, getstr, getary, getdct = StringScanner.new(str)
getvalue = ->{
if ss.scan /\s*\{\s*/ then getdct[]
elsif ss.scan /\s*\(\s*/ then getary[]
elsif str = getstr[] then str
elsif ss.scan /\s*[)}]\s*/ then nil end
}
getstr = ->{
if str=ss.scan(/\s*"(?:[^"\\]|\\u\d+|\\.)*"\s*/i)
eval str.gsub(/([^\\](?:\\\\)*)#(?=[{@$])/,'\1\#')
end
}
getary = ->{
[].tap do |a|
while v=getvalue[]
a << v
ss.scan /\s*,\s*/
end
end
}
getdct = ->{
{}.tap do |h|
while key = getstr[]
ss.scan /\s*=\s*/
if value=getvalue[] then h[key]=value; ss.scan(/\s*;\s*/) end
end
end
end
}
getvalue[]
end
作为将来从头开始编译自己的解析器的替代方法,您可能还需要查看Treetop Ruby库。
编辑:我已将上面getstr
的实现替换为应该阻止在eval
内运行任意Ruby代码的实现。有关详细信息,请参阅 "Eval a string without interpolation" 。见过:
@secret = "OH NO!"
$secret = "OH NO!"
@@secret = "OH NO!"
puts parse('"\"#{:NOT&&:very}\" bad. \u262E\n#@secret \\#$secret \\\\#@@secret"')