解析来自红宝石特定类JSON数据(NEXTSTEP的plist)(Parsing specific

2019-10-18 03:57发布

我正在写一个客户端第三方API,它们提供一个奇怪的格式的数据。 起初,它可能看起来像JSON,但它不是,我有点困惑,我应该如何处理。

这是一个基于密钥值格式(很像JSON)。

  • 密钥由“=”从它们的值分开。
  • 键和值在双引号内包裹着。
  • 字典开始“{”和结束“}”。
  • 数组开始“(”和结尾“)”
  • 线结束与“;” (为的例外阵列含量)和结束行字符(\ RI认为)。
  • 有时,似乎是Unicode(东西一样\ U2623的生化危机符号)的字符串。

怎么可能是这种格式? 要我用一个预制的宝石解析它,或者我应该建立自己的解析器?

{ "anArray" = (
  "100",
  "200",
  "300"
  );
  "aDictionary" = {
    "aString" = "Something";
  };
}

编辑这种格式似乎是苹果公司的财产清单,但由于API是从web服务的WebObjects它不是XML二进制都不...这是有意义的。 我将尝试使用CFPropertyList宝石解析它,如果有一个更好的解决方案,请让我知道。

编辑2这是NeXTSTEP的财产清单 。

Answer 1:

下面是一个使用自定义的一个强大的答案StringScanner基于解析器。 它允许空白是可选的,允许尾随在列表中最后一个项目之后的逗号,并允许省略最后的字典键/值对后的分号。 它允许最外面的项目是一个字典,数组或字符串。 它真的可以让任何形式的法律字符串内容,包括括号和大括号,逃到如文本\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

作为替代方案,以在将来刮滚动自己的解析器,你可能也想看看在树梢 Ruby库。


编辑 :我已经更换了实施getstr上面一个应该防止运行中的任意Ruby代码eval 。 有关详细信息,请参阅“评估和演示不插一个字符串” 。 看在行动:

@secret = "OH NO!"
$secret = "OH NO!"
@@secret = "OH NO!"
puts parse('"\"#{:NOT&&:very}\" bad. \u262E\n#@secret \\#$secret \\\\#@@secret"')


Answer 2:

这里是一个非常快速和肮脏的黑客工具,变换语法为有效的Ruby,然后evals它。 请注意,这可能是危险的。 更重要的是,这将里面的键和值全部括号转换为方括号。

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"}}


文章来源: Parsing specific JSON-like data (NextSTEP PList) from Ruby