繁体   English   中英

如何在 Ruby 中没有已知深度的情况下迭代深度嵌套的 hash

[英]How to iterate over deep nested hash without known depth in Ruby

我有多个 YAML(本地化)文件。 我解析它们并在 Ruby 中转换为 hash。

例如,这是其中之一:

hello: Hallo
messages:
  alerts:
    yay: Da!
    no: Nein
  deep:
    nested:
      another:
        level:
          hi: Hi!
test: Test!

基本上,这看起来像是 Rails App 中使用 YAML 的语言环境文件。

我想要做的是递归地迭代这个 Hash 并获取键和值。 这样我就可以像谷歌翻译一样从 API 端点逐一翻译值。 我想将嵌套哈希保留在相同的模式中,以便 Rails 可以通过键找到。

我知道我可以使用嵌套循环,但不能保证嵌套哈希是已知数量的。 如何递归地迭代这个 hash 以便我可以操纵值(翻译/替换)?

预期结果:(使用 API 调用的翻译服务后

hello: Hello
messages:
  alerts:
    yay: Yup!
    no: No
  deep:
    nested:
      another:
        level:
          hi: Hi!
test: Test!

到目前为止我已经尝试过:

hash = YAML.load('de.yml') # parse source Deutsch locale 
new_hash = {}

hash.each |key, value| do
  new_hash[key] = translate_func(value) # here... translate value then assign very same key including parents.

  # Do more loops....
end

# Now write this new_hash to yaml file...

但这只是操纵hello而已。 为了和其他人一起工作,我必须做一个循环。 但是嵌套了多少键是未知的。

如何遍历区域设置 hash 的所有值并保持架构完整?

如果可能但不是强制性的,如果我们能在最终结果中保持键的顺序,我会非常高兴。 稍后在手动查看时找到丢失的键会很棒。

我对 ruby 很陌生。 我正在使用 Ruby 2.7.2

结论/解决

所有答案都是正确的,我喜欢所有答案。 但是,我希望能够同时控制键和值。 不只是通过价值观转变。 因此,我接受了一个适合我需要的答案。 我能够用选定的答案来完成我的意图。

您可以使用deep_transform_values! 在您的 hash object 上以递归方式更改值。 (或其非破坏性版本deep_transform_values返回一个新的 hash 而不是更改原始 hash。)

hash.deep_transform_values! { |value| translate_func(value) }

注意: deep_transform_values! 是一种 Rails 方法。 如果您不使用 Rails,请参阅此处的源代码以获得灵感。

因此,您希望递归解析,直到没有更多级别可供解析。

它在软件中非常常见,被称为“递归”。 到处搜索以了解更多信息 - 它会在您的旅程中一次又一次地出现。 欢迎来到 ruby 顺便说一句!

至于您当前的实际问题。 阅读https://mrxpalmeiras.wordpress.com/2017/03/30/how-to-parse-a-nested-yaml-config-file-in-python-and-ruby/

而且,考虑一下 i18n gem。 请参阅此答案https://stackoverflow.com/a/51216931/1777331和 gem https://github.com/ruby-i18n/i18n的文档这可能会解决您在没有您的情况下处理国际化的问题处理 yaml 文件的详细信息。

如果您想要一个简单的非 Rails 解决方案,那么您可以创建一个递归方法:

def recurse(hash)
  hash.transform_values do |v|
    case v
    when String
      v.reverse # Just for the sake of the example
    when Hash
      recurse(v)
    else
      v
    end
  end
end

Output:

{"hello"=>"ollaH", "messages"=>{"alerts"=>{"yay"=>"!aD", false=>"nieN"}, "deep"=>{"nested"=>{"another"=>{"level"=>{"hi"=>"!iH"}}}}}, "test"=>"!tseT"}

然而,这可能是重新发明轮子的情况 - 您可以使用 i18n gem 进行翻译,并使用i18n 任务使用来自 Google 翻译 API 的翻译预填充 YAML 文件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM