最佳方法美化打印哈希表

214

我有一个包含嵌套数组和哈希的大哈希表。 我希望能够简单地将其输出,使用户能够“可读”。

我希望它类似于to_yaml - 那非常易懂 - 但看起来仍然太技术化。

最终需要让终端用户阅读这些数据块,因此它们需要被整洁地格式化。

有任何建议吗?


可能是[如何使IRB打印数组和哈希结构的结构](https://dev59.com/3HRB5IYBdhLWcg3wJkhC)的重复问题。 - Martin Thoma
在线工具http://jsonviewer.stack.hu。但是对于哈希火箭语法它不能正常工作。 - Amit Patel
14个回答

307
require 'pp'
pp my_hash

如果你需要一个内置的解决方案并且只想要合理的换行,请使用pp

如果你可以安装 gem,那么请使用awesome_print。(根据你的用户,你可能希望使用index:false选项来关闭显示数组索引。)


PP很好,但遗憾的是我们无法限制深度。 - akim

125

这个答案如果有一个实际的例子会更有帮助。 - Travis Bear
@TravisBear 如果您单击我的答案中的“另请参阅”链接,将会看到示例输出。我特别推荐这个答案:https://dev59.com/VnVD5IYBdhLWcg3wGXpI#1823885 - David J.
15
这句话的意思是“执行puts JSON.pretty_generate(hash)”。 - joeloui
如果您确实需要创建JSON,请允许我推荐我自己的(免费,开源,无广告)库,用于从Ruby或JS创建漂亮的JSON:NeatJSON(Ruby)NeatJSON(在线/JS) - Phrogz
抱歉,我现在意识到 pretty_generate 接受的是 Ruby 对象,而不是 JSON 文本。 - Tony

37

对我来说比ppawesome_print更好的解决方案:

require 'pry' # must install the gem... but you ALWAYS want pry installed anyways
Pry::ColorPrinter.pp(obj)

3
注意,Pry::ColorPrinter.pp(obj) 会将内容写入标准输出,但可以使用额外的参数,包括目标输出位置。例如 Pry::ColorPrinter.pp(obj, a_logger) - Eric Urban
1
我很惊讶这个没有更好的文档说明:我一直使用pry作为我的Rails控制台,而且我已经寻找了很长时间如何在不使用其他gem的情况下进入它的漂亮打印机。点赞,因为这个解决方案终于结束了我漫长的搜索。 :-) - wiz

23

如果您没有任何高级的Gem操作,但是有JSON,那么这个CLI命令可以用于一个哈希表:

puts JSON.pretty_generate(my_hash).gsub(":", " =>")

#=>
{
  :key1 => "value1",

  :key2 => "value2",

  :key3 => "value3"
}

9
因为这样会破坏包含 ":" 的键和值,所以被投反对票。 - thomax
1
这也没有涉及到 null (JSON) 与 nil (Ruby) 的区别。 - Rennex
1
大多数情况下仍然很方便。 - Abram
1
三年后,真不敢相信!感谢 @Abram。 :) 这可能不是世界上最优雅的解决方案,但在紧急情况下它能解决问题。 - Nick Schwaderer
我对JSON.pretty_generate(my_hash)感到非常满意。 - Jared Menard

6
用纯 Ruby(不用 gem)漂亮打印 Hash
我看到这个帖子时正试图解决这个问题。我有一个很大的 Hash,想要将其美化,但我需要保留 ruby hash 记法而不是 JSON。
以下是代码和示例:
- 使用 pretty_generate 获取格式良好的 JSON 字符串。 - 用对应的 symbol: 替换所有的 JSON 键。
puts JSON.pretty_generate(result)
         .gsub(/(?:\"|\')(?<key>[^"]*)(?:\"|\')(?=:)(?:\:)/) { |_|
              "#{Regexp.last_match(:key)}:"
          }

示例JSON

{
  "extensions": {
    "heading": "extensions",
    "take": "all",
    "array_columns": [
      "name"
    ]
  },
  "tables": {
    "heading": "tables",
    "take": "all",
    "array_columns": [
      "name"
    ]
  },
  "foreign_keys": {
    "heading": "foreign_keys",
    "take": "all",
    "array_columns": [
      "name"
    ]
  },
  "all_indexes": {
    "heading": "all_indexes",
    "take": "all",
    "array_columns": [
      "name"
    ]
  },
  "keys": {
    "heading": "keys",
    "take": "all",
    "array_columns": [
      "name"
    ]
  }
}

样例 Ruby 哈希表

{
  extensions: {
    heading: "extensions",
    take: "all",
    array_columns: [
      "name"
    ]
  },
  tables: {
    heading: "tables",
    take: "all",
    array_columns: [
      "name"
    ]
  },
  foreign_keys: {
    heading: "foreign_keys",
    take: "all",
    array_columns: [
      "name"
    ]
  },
  all_indexes: {
    heading: "all_indexes",
    take: "all",
    array_columns: [
      "name"
    ]
  },
  keys: {
    heading: "keys",
    take: "all",
    array_columns: [
      "name"
    ]
  }
}

жИСиЃ§дЄЇ\"|\'йГљеЇФиѓ•зЃАеНХеЬ∞жФєдЄЇ\"пЉМеЫ†дЄЇJSON.generateдЄНдЉЪзФ®'еМЕеЫійФЃгАВ - Alexey Romanov

5

在Rails中

如果你需要一个“漂亮打印”的哈希表,例如在Rails.logger 中使用, 那么这个方法很适合你。具体来说,它会运行哈希表中对象的 inspect 方法,如果你按照规范重写/定义了你的对象的 inspect 方法,则非常有用。

  • 这个方法有良好的展示效果,特别是当哈希表越大越嵌套的时候,效果越明显。
logger.error my_hash.pretty_inspect

例如:
class MyObject1
  def inspect
    "<#{'*' * 10} My Object 1 #{'*' * 10}>"
  end
end

class MyObject2
  def inspect
    "<#{'*' * 10} My Object 2 #{'*' * 10}>"
  end
end

my_hash = { a: 1, b: MyObject1.new, MyObject2.new => 3 }

Rails.logger.error my_hash
# {:a=>1, :b=><********** My Object 1 **********>, <********** My Object 2 **********>=>3}

# EW! ^

Rails.logger.error my_hash.pretty_inspect
# {:a=>1,
#  :b=><********** My Object 1 **********>,
#  <********** My Object 2 **********>=>3}

pretty_inspect 来自PrettyPrint,Rails默认包含它。因此,无需使用gems或将其转换为JSON。

不在Rails中

如果您不在Rails中或由于某些原因上述方法失败,请先尝试使用require "pp"。例如:

require "pp"  # <-----------

class MyObject1
  def inspect
    "<#{'*' * 10} My Object 1 #{'*' * 10}>"
  end
end

class MyObject2
  def inspect
    "<#{'*' * 10} My Object 2 #{'*' * 10}>"
  end
end

my_hash = { a: 1, b: MyObject1.new, MyObject2.new => 3 }

puts my_hash
# {:a=>1, :b=><********** My Object 1 **********>, <********** My Object 2 **********>=>3}

# EW! ^

puts my_hash.pretty_inspect
# {:a=>1,
#  :b=><********** My Object 1 **********>,
#  <********** My Object 2 **********>=>3}

一个完整的例子

这是我项目中用pretty_inspect方法生成的哈希表样例,为保护对象隐私,已经替换成了特定文本:

{<***::******************[**:****, ************************:****]********* * ****** ******************** **** :: *********** - *** ******* *********>=>
  {:errors=>
    ["************ ************ ********** ***** ****** ******** ***** ****** ******** **** ********** **** ***** ***** ******* ******",
     "************ ************ ********** ***** ****** ******** ***** ****** ******** **** ********** is invalid",
     "************ ************ ********** ***** ****** ******** is invalid",
     "************ ************ ********** is invalid",
     "************ ************ is invalid",
     "************ is invalid"],
   :************=>
    [{<***::**********[**:****, *************:**, ******************:*, ***********************:****] :: **** **** ****>=>
       {:************=>
         [{<***::***********[**:*****, *************:****, *******************:**]******* :: *** - ******* ***** - *>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: *** - *>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ********* - *>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ********** - ********** *>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ******** - *>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: **** - *******>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: *** - ********** ***** - *>=>
            {}}]}},
     {<***::**********[**:****, *************:**, ******************:*, ***********************:****] ******************** :: *** - *****>=>
       {:errors=>
         ["************ ********** ***** ****** ******** ***** ****** ******** **** ********** **** ***** ***** ******* ******",
          "************ ********** ***** ****** ******** ***** ****** ******** **** ********** is invalid",
          "************ ********** ***** ****** ******** is invalid",
          "************ ********** is invalid",
          "************ is invalid"],
        :************=>
         [{<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - ********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - ********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *******>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]*********** :: ****>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *******>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *******>=>
            {:errors=>
              ["********** ***** ****** ******** ***** ****** ******** **** ********** **** ***** ***** ******* ******",
               "********** ***** ****** ******** ***** ****** ******** **** ********** is invalid",
               "********** ***** ****** ******** is invalid",
               "********** is invalid"],
             :**********************=>
              [{<***::*******************[**:******, ************************:***]****-************ ******************** ***: * :: *** - ***** * ****** ** - ******* * **: *******>=>
                 {:errors=>
                   ["***** ****** ******** **** ********** **** ***** ***** ******* ******",
                    "***** ****** ******** **** ********** is invalid"],
                  :***************=>
                   [{<***::********************************[**:******, *************:******, ***********:******, ***********:"************ ************"]** * *** * ****-******* * ******** * ********* ******************** *********************: ***** :: "**** *" -> "">=>
                      {:errors=>["**** ***** ***** ******* ******"],
                       :**********=>
                        {<***::*****************[**:******, ****************:["****** ***", "****** ***", "****** ****", "******* ***", "******* ****", "******* ***", "****"], **:""] :: "**** *" -> "">=>
                          {:errors=>
                            ["***** ******* ******",
                             "***** ******* ******"]}}}}]}}]}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:**]******* :: ****** - ** - *********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - ********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - **********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - **********>=>
            {}},
          {<***::***********[**:*****, *************:****, *******************:***]******* :: ****** - ** - **********>=>
            {}}]}}]}}

4

如果你想把内容打印给用户看,使用上面的答案。

如果你只是在控制台中为自己打印,我建议使用pry gem而不是irb。除了漂亮的打印外,pry还有很多其他功能(请查看下面的railscast)

gem install pry

并查看此railscast:

http://railscasts.com/episodes/280-pry-with-rails


3

如果您相信您的键是健全的,那么使用json很容易实现:

JSON.pretty_generate(a: 1, 2 => 3, 3 => nil).
  gsub(": null", ": nil").
  gsub(/(^\s*)"([a-zA-Z][a-zA-Z\d_]*)":/, "\\1\\2:"). # "foo": 1 -> foo: 1
  gsub(/(^\s*)(".*?"):/, "\\1\\2 =>") # "123": 1 -> "123" => 1

{
  a: 1,
  "2" => 3,
  "3" => nil
}

1
使用Pry,你只需要将以下代码添加到你的~/.pryrc中:
require "awesome_print"
AwesomePrint.pry!

这个程序会将每个命令都进行漂亮的打印输出。我希望它能够在指令上进行漂亮的打印输出,例如当我在命令前使用 pp 命令时,像这样 - pp User.last。 - Divij Jain

1
在我尝试过的所有宝石中,show_data 宝石对我来说效果最好,我现在经常使用它来记录 Rails 中的参数哈希。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接