我正在尝试从YAML文件加载单词列表。在文件中有一个条目
- on
Ruby将此加载为" true"而不是" on"。同样地" off"加载为" false"。快速检查心理代码显示"是"和"不"以同样的方式对待。
除了在on和off周围添加引号之外,我有什么办法可以改变这种行为吗?
如果我读取文件并解析,而不是load_file,我能够看到这些值。
# test.yaml
- true
- false
- yes
- no
- on
- off
- y
- n
- Y
- N
我通过解析而不是加载得到一个Psych文档,它在转换为native之前有文本。
YAML.parse_file('test.yaml')
想知道如何正确提取它。
来自文档
"表示阶段表示已组成YAML :: BaseNode对象的数据。在此阶段,文档可用作节点对象树。您可以在此级别执行YPath查询和转换。 (参见YAML :: parse。)"
需要有关编写全面YPath查询以提取数据的帮助。
(PS:这看起来有点迂回,但这为我清理了很多数据管理方面的事情)
答案 0 :(得分:3)
它列在YAML reference card上,但我在规范中找不到任何引用。
Language Independent Scalar types: ... { Y, true, Yes, ON } : Boolean true { n, FALSE, No, off } : Boolean false ...
我认为报价是你唯一的选择。
答案 1 :(得分:1)
正如其他答案中已经解释过的那样,on
被视为" truthy"值。此行为是intentionally coded in Psych。
正如Arup Rakshit和Mikhail P所解释的那样,问题的最佳解决方案是引用该值。但是,鉴于您的问题要求替代方案,这里有一个替代方案。
Psych中的标量转换在Psych::ScalarScanner#tokenize
中是硬编码的。可能(但强烈反对)选项是修改此方法以更改此case statement
when /^(yes|true|on)$/i
true
when /^(no|false|off)$/i
false
正如您可能已经意识到查看源代码一样,该方法很长,并且猴子补丁会强制您复制/粘贴相当大的代码块。没有简单的方法,选项被硬编码到精选案例中(还有一个迹象表明这不是一个好主意)。
就个人而言,我永远不会这样。修改Psych的核心行为可能会导致一些意想不到的副作用,因为其他库可能依赖于此行为。
如果您不想在物理上修改原始文件,另一个选择是编写一个在运行时更改它的代理。
实际上,您可以创建一个实现parse_file
方法的CustomYaml解析器。该方法将读取内存中文件的内容,执行"搜索&替换"任何未转义on
到"on"
的情况,然后感觉YAML.load()
。
这会欺骗YAML
解析,导致它解释每个" on"令牌作为标量字符串。
与此预处理方法类似,您可以通过遍历Psych返回的YAML AST来采用后处理方法。
答案 2 :(得分:0)
正如您所暗示的那样,通过修改AST来使其正常工作。
代码如下:
src = YAML.parse(data)
src.select{ |node| node.is_a?(Psych::Nodes::Scalar) &&
%w(on off).include?(node.value) }
.each{|node| node.quoted = true }
所以基本上,这只是欺骗系统认为引用了值为on
和off
的所有值节点。这使他们看起来像字符串。
当然,这是依赖于实现的,对于除了Psych之外的其他人,这必须以不同的方式完成。
答案 3 :(得分:0)
这似乎符合我目前的要求。
require 'yaml'
ydoc = YAML.parse_file('test.yaml')
puts ydoc.children.map { |sequence| sequence.children.map { |scalar| scalar.value }}
"孩子"帮助从心理文件向下移动>心理序列>心理标量。
请告诉我你的意见。