如何排序YAML文件?

时间:2011-09-01 20:13:23

标签: ruby sorting internationalization yaml

我一直在尝试用Ruby对i18n翻译YAML文件进行排序,这样我就能以更好,更有条理的方式管理新的翻译,但我一直想知道是否有什么可以轻松完成任务。

我找到了一个YAML文件编写器,所以我可以将哈希写入文件,但我的问题是正确地对哈希进行排序。如果我得到哈希hh.sort会返回一个数组,但我仍然没有想出一个简单的方法。

我有这样的YAML文件:

pt-br:    
  global:
    misc:
      total: "Total"
      all: "Todos"
      close: "Fechar"
      cancel: "Cancelar"

    crud:
      access: "Acessar"
      back: "Voltar"
      edit: "Editar"
      confirm: "Confirmar"
      send: "Enviar"

...

(文件大于此)

但我想用这种方式对它们进行排序:

pt-br:    
  global:
    crud:
      access: "Acessar"
      back: "Voltar"
      confirm: "Confirmar"
      edit: "Editar"
      send: "Enviar"

    misc:
      all: "Todos"
      cancel: "Cancelar"
      close: "Fechar"          
      total: "Total"

我认为一些简单的递归方法可以帮助我这样:

def translation_sort(h)
  if h.class == Hash
    h = h.sort
    h.each{|item| translation_sort(item)}
  end
  h
end

require "yaml"
h=YAML.load_file(File.open("~/pt-br.sample.yml"))
translation_sort(h)

9 个答案:

答案 0 :(得分:10)

实际上这是一个很好的问题。你想深刻排序哈希。所以我不喜欢重新发明轮子,然后我搜索了一个很好的实现,我找到了一个我喜欢的。看看它https://gist.github.com/1083930。它工作正常。

答案 1 :(得分:9)

您不应该像其他答案中建议的那样使用YAML库。当你使用重音符号和特殊字符时,它会搞砸长字符串值的格式,删除你的注释并吐出不可读的字符转义符(你会这样做,因为你正在做i18n)。 使用我创建的这个宝石:

https://github.com/redealumni/i18n_yaml_sorter

它只会对文件中的行进行排序,因此所有内容都将保持原始yaml(您的重音符号,用于输入字符串的YAML构造,缩进等)的方式。它将与深度嵌套的yamls一起使用,结果非常可靠。宝石包括测试,它对红宝石1.8或1.9都有好处。

它附带一个TextMate Bundle(Shift + Command + S)和一个Rails rake任务,因此您可以在编辑器中轻松地立即对文件进行排序。这真的很快。

说明不同之处:

原件:

  pt-BR:
    # Note how this is a nice way of inputing
    # paragraphs of text in YAML. 
    apples: >
      Maçãs são boas,
      só não coma 
      seus iPods!
    grapes: Não comemos elas.
    bananas: |
      Bananas são "legais":
        - Elas são <b> doces </b>.
        isto: não é chave

      Por isto todos gostam de bananas!

YAML :: dump的结果:

  pt-BR: 
    apples: "Ma\xC3\xA7\xC3\xA3s s\xC3\xA3o boas, s\xC3\xB3 n\xC3\xA3o coma  seus iPods!\n"
    bananas: "Bananas s\xC3\xA3o \"legais\":\n  - Elas s\xC3\xA3o <b> doces </b>.\n  isto: n\xC3\xA3o \xC3\xA9 chave\n\n\ Por isto todos gostam de bananas!\n"
    grapes: "N\xC3\xA3o comemos elas."

i18n_yaml_sorter的结果:

  pt-BR:
    # Note how this is a nice way of inputing
    # paragraphs of text in YAML. 
    apples: >
      Maçãs são boas,
      só não coma 
      seus iPods!
    bananas: |
      Bananas são "legais":
        - Elas são <b> doces </b>.
        isto: não é chave

      Por isto todos gostam de bananas!
    grapes: Não comemos elas.

答案 2 :(得分:7)

https://gist.github.com/1083930无法正常工作。它只对哈希键进行深度排序,但是哈希值也是哈希值。在我需要深度排序哈希的用例中,哈希总是一棵树,其中键是标签,值是(子)树(如果是哈希)或叶子(否则)。我只需要对树的标签进行深度排序。

我得到了这个

before: {"a":[2,10,{"5":null,"1":null,"3":null}],"x":{"5":null,"1":null,"3":null},"a2":{"5":[2,10,5],"1":null,"3":null}}
after:  {"a":[2,10,{"5":null,"1":null,"3":null}],"a2":{"1":null,"3":null,"5":[2,10,5]},"x":{"1":null,"3":null,"5":null}}

用这个

require 'active_support'

def deeply_sort_hash(object)
  return object unless object.is_a?(Hash)
  hash = RUBY_VERSION >= '1.9' ? Hash.new : ActiveSupport::OrderedHash.new
  object.each { |k, v| hash[k] = deeply_sort_hash(v) }
  sorted = hash.sort { |a, b| a[0].to_s <=> b[0].to_s }
  hash.class[sorted]
end

答案 3 :(得分:6)

2014年4月更新:

使用 Rails 3 .2.13, Ruby 1.9 .3p489:

我刚刚使用了i18n_yaml_sorter gem(https://github.com/redealumni/i18n_yaml_sorter)。

只需添加到您的Gemfile

gem 'i18n_yaml_sorter', group: :development

然后运行 rake任务以对您的区域设置进行排序&#39;文件:

rake i18n:sort

工作完美,即使宝石最后一次创作于2年前。最多花了5分钟

答案 4 :(得分:1)

在Ruby 1.8中,哈希没有特定的顺序,所以你不能只对它们进行排序。

你可以像这样修补/覆盖to_yaml的{​​{1}}方法:

Hash

当然,具体细节可能取决于您的YAML / Ruby版本。以上示例适用于Ruby 1.8.6。

答案 5 :(得分:1)

这是另一个遇到此问题的人的另一种选择..

require 'yaml'

yaml = YAML.load(IO.read(File.join(File.dirname(__FILE__), 'example.yml')))

@yml_string = "---\n"

def recursive_hash_to_yml_string(hash, depth=0)
  spacer = ""
  depth.times { spacer += "  "}
  hash.keys.sort.each do |sorted_key|
    @yml_string += spacer + sorted_key + ": "
    if hash[sorted_key].is_a?(Hash)
      @yml_string += "\n"
      recursive_hash_to_yml_string(hash[sorted_key], depth+1)
    else
      @yml_string += "#{hash[sorted_key].to_s}\n"
    end
  end
end

recursive_hash_to_yml_string(yaml)

open(File.join(File.dirname(__FILE__), 'example.yml'), 'w') { |f|
  f.write @yml_string
}

答案 6 :(得分:1)

还有一个原子包可以执行此操作https://github.com/akfernun/yaml-sortkeys

答案 7 :(得分:0)

这可能是另一个吸引人的选择:https://github.com/redealumni/i18n_yaml_sorter

答案 8 :(得分:0)

很遗憾,YAML::quick_emit已过时,在Psych gem的较新版本中不再可用。如果您希望在将哈希键序列化为yaml时对其进行排序,则必须使用以下猴子补丁:

class Hash
    def to_yaml opts={}
        return Psych.dump(self.clone.sort.to_h)
    end
end