【问题标题】:How do I check if a string is valid YAML?如何检查字符串是否为有效的 YAML?
【发布时间】:2013-05-02 01:39:38
【问题描述】:

我想检查一个字符串是否是有效的 YAML。我想在我的 Ruby 代码中使用 gem 或库来执行此操作。我只有这个 begin/rescue 子句,但它没有得到正确的救援:

def valid_yaml_string?(config_text)
  require 'open-uri'
  file = open("https://github.com/TheNotary/the_notarys_linux_mint_postinstall_configuration")
  hard_failing_bad_yaml = file.read
  config_text = hard_failing_bad_yaml
  begin
    YAML.load config_text
    return true
  rescue
    return false
  end
end

不幸的是,我遇到了以下严重错误:

irb(main):089:0> valid_yaml_string?("b")
Psych::SyntaxError: (<unknown>): mapping values are not allowed in this context at line 6 column 19
from /home/kentos/.rvm/rubies/ruby-1.9.3-p374/lib/ruby/1.9.1/psych.rb:203:in `parse'
from /home/kentos/.rvm/rubies/ruby-1.9.3-p374/lib/ruby/1.9.1/psych.rb:203:in `parse_stream'
from /home/kentos/.rvm/rubies/ruby-1.9.3-p374/lib/ruby/1.9.1/psych.rb:151:in `parse'
from /home/kentos/.rvm/rubies/ruby-1.9.3-p374/lib/ruby/1.9.1/psych.rb:127:in `load'
from (irb):83:in `valid_yaml_string?'
from (irb):89
from /home/kentos/.rvm/rubies/ruby-1.9.3-p374/bin/irb:12:in `<main>'

【问题讨论】:

    标签: ruby yaml


    【解决方案1】:

    使用代码的清理版本:

    require 'yaml'
    require 'open-uri'
    
    URL = "https://github.com/TheNotary/the_notarys_linux_mint_postinstall_configuration"
    
    def valid_yaml_string?(yaml)
      !!YAML.load(yaml)
    rescue Exception => e
      STDERR.puts e.message
      return false
    end
    
    puts valid_yaml_string?(open(URL).read)
    

    我明白了:

    (<unknown>): mapping values are not allowed in this context at line 6 column 19
    false
    

    当我运行它时。

    原因是,您从该 URL 获取的数据根本不是 YAML,而是 HTML:

    open('https://github.com/TheNotary/the_notarys_linux_mint_postinstall_configuration').read[0, 100]
    => "  \n\n\n<!DOCTYPE html>\n<html>\n  <head prefix=\"og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# githubog:"
    

    如果您只想要一个真/假响应,无论它是可解析的 YAML,请删除此行:

    STDERR.puts e.message
    

    不幸的是,超出此范围并确定字符串是否为 YAML 字符串变得更加困难。你可以做一些嗅探,寻找一些提示:

    yaml[/^---/m]
    

    将搜索 YAML“文档”标记,但 YAML 文件不必使用这些标记,它们也不必位于文件的开头。我们可以添加它来加强测试:

    !!YAML.load(yaml) && !!yaml[/^---/m]
    

    但是,即使这样也会留下一些漏洞,因此添加一个测试以查看解析器返回的内容会更有帮助。 YAML 可以返回 Fixnum、String、Array 或 Hash,但如果您已经知道会发生什么,您可以查看 YAML 想要返回的内容。例如:

    YAML.load(({}).to_yaml).class
    => Hash
    YAML.load(({}).to_yaml).instance_of?(Hash)
    => true
    

    所以,你可以寻找一个哈希:

    parsed_yaml = YAML.load(yaml)
    !!yaml[/^---/m] && parsed_yaml.instance_of(Hash) 
    

    Hash 替换为您认为应该得到的任何类型。

    可能有更好的方法来嗅出它,但这些是我首先尝试的。

    【讨论】:

    • 在 IRB 中尝试!true,然后尝试!!true,然后尝试!('foo'=='foo'),然后尝试!!('foo'=='foo')
    • 谢谢铁皮人!说得好。这是我偶然发现的谷歌的一个严重漏洞(我忘记输入救援表达式)。关于 !!,我认为在 !!nil 之类的情况下,当您想要一个方法返回 true 或 false,而不是 nil 或字符串时,这一定很有用?非常整洁,再次感谢。
    • 是的,!! 是一个很好的简写,可以强制做出正确/错误的响应。它适用于任何将! 用于逻辑非的语言。
    • 嘘!多么完美的解释,太棒了,喜欢它:)
    • Tin Man 的回答很好,但我认为您的最后一个示例可能需要更新 !!yaml[/^---/m] &amp;&amp; parsed_yaml.instance_of?(Hash)
    猜你喜欢
    • 1970-01-01
    • 2018-02-02
    • 2011-02-26
    • 2021-10-03
    • 2011-06-17
    • 2013-02-13
    • 1970-01-01
    • 2016-01-15
    • 2018-06-15
    相关资源
    最近更新 更多