gpt4 book ai didi

ruby - 为每个键加载带有行号的 YAML

转载 作者:数据小太阳 更新时间:2023-10-29 06:58:25 27 4
gpt4 key购买 nike

假设我有一个如下所示的 YAML 文件:

  en:    errors:      # Some comment      format: "%{attribute} %{message}"      # One more comment      messages:        "1": "Message 1"        "2": "Message 2"    long_error_message: |      This is a      multiline message    date:      format: "YYYY-MM-DD"

How can I read this into a Ruby Hash like this?

{
'en': {
'errors': {
'format': { value: '%{attribute} %{message}', line: 4 }
'messages': {
'1': { value: 'Message 1', line: 8 },
'2': { value: 'Message 2', line: 9 }
}
'long_error_message' : { value: "This is a\nmultiline message", line: 11 }
},
'date': {
'format': { value: 'YYYY-MM-DD', line: 16 }
}
}
}

我试过使用 YAML: Find line number of key? 中提到的技巧作为起点并实现了 Psych::Handler,但感觉我必须重写 Psych 中的大量代码才能使其正常工作。

有什么办法可以解决这个问题吗?

最佳答案

看起来你想要获取作为映射值的任何标量值,并将其替换为具有包含原始值的 value 键和 line 的散列带有行号的键。

以下几乎可以工作,主要问题是多行字符串,其中给定的行号是 Yaml 中下一个内容的开始。问题是当调用处理程序 scalar 方法时,解析器已经超出了感兴趣的标量,因此 mark 给出了位置的行知道标量已经结束。在您的示例中的大多数情况下,这无关紧要,但对于多行情况,它会给出错误的值。如果不进入 Psych C 代码,我看不出有任何方法可以从 mark 获取标量开头的解析器信息。

require 'psych'

# Psych's first step is to parse the Yaml into an AST of Node objects
# so we open the Node class and add a way to track the line.
class Psych::Nodes::Node
attr_accessor :line
end

# We need to provide a handler that will add the line to the node
# as it is parsed. TreeBuilder is the "usual" handler, that
# creates the AST.
class LineNumberHandler < Psych::TreeBuilder

# The handler needs access to the parser in order to call mark
attr_accessor :parser

# We are only interested in scalars, so here we override
# the method so that it calls mark and adds the line info
# to the node.
def scalar value, anchor, tag, plain, quoted, style
mark = parser.mark
s = super
s.line = mark.line
s
end
end

# The next step is to convert the AST to a Ruby object.
# Psych does this using the visitor pattern with the ToRuby
# visitor. Here we patch ToRuby rather than inherit from it
# as it makes the last step a little easier.
class Psych::Visitors::ToRuby

# This is the method for creating hashes. There may be problems
# with Yaml mappings that have tags.
def revive_hash hash, o
o.children.each_slice(2) { |k,v|
key = accept(k)
val = accept(v)

# This is the important bit. If the value is a scalar,
# we replace it with the desired hash.
if v.is_a? ::Psych::Nodes::Scalar
val = { "value" => val, "line" => v.line + 1} # line is 0 based, so + 1
end

# Code dealing with << (for merging hashes) omitted.
# If you need this you will probably need to copy it
# in here. See the method:
# https://github.com/tenderlove/psych/blob/v2.0.13/lib/psych/visitors/to_ruby.rb#L333-L365

hash[key] = val
}
hash
end
end

yaml = get_yaml_from_wherever

# Put it all together
handler = LineNumberHandler.new
parser = Psych::Parser.new(handler)
# Provide the handler with a reference to the parser
handler.parser = parser

# The actual parsing
parser.parse yaml
# We patched ToRuby rather than inherit so we can use to_ruby here
puts handler.root.to_ruby

关于ruby - 为每个键加载带有行号的 YAML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29462856/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com