59

我正在生成一个将信息输出到控制台的脚本。信息是某种具有价值的统计数据。非常像哈希。

因此,一个值的名称可能是 8 个字符长,另一个是 3 个字符。当我循环输出带有两个 \t 的信息时,某些列未正确对齐。

因此,例如输出可能是这样的:

long value name          14
short              12
little             13
tiny               123421
long name again          912421

我希望所有值都正确排列。现在我正在这样做:

puts "#{value_name} - \t\t #{value}"

我怎么能说长名字,只使用一个标签?还是有其他解决方案?

4

7 回答 7

58

如果您知道最大长度不超过 20 个字符:

printf "%-20s %s\n", value_name, value

如果你想让它更有活力,这样的事情应该可以很好地工作:

longest_key = data_hash.keys.max_by(&:length)
data_hash.each do |key, value|
  printf "%-#{longest_key.length}s %s\n", key, value
end
于 2009-07-06T15:54:29.143 回答
24

通常有%10s一种printf格式很好的方案。
但是,我根本没有使用过 ruby​​,所以你需要检查一下。


是的,有格式化的 printf。
上面的示例应该在 10 个字符的空间内右对齐。
您可以根据列中最宽的字段进行格式化。

printf ([端口, ]格式, arg...)

打印根据 sprintf 等格式格式化的参数。如果第一个参数是 IO 或其子类的实例,则打印重定向到该对象。默认值是 $stdout 的值。

于 2009-07-06T15:38:49.653 回答
21

String 有一个内置的ljust正是为了这个:

x = {"foo"=>37, "something long"=>42, "between"=>99}
x.each { |k, v| puts "#{k.ljust(20)} #{v}" }
# Outputs:
#  foo                  37
#  something long       42
#  between              99

或者,如果你想要标签,你可以做一些数学运算(假设标签显示宽度为 8)并编写一个简短的显示函数:

def tab_pad(label, tab_stop = 4)
  label_tabs = label.length / 8
  label.ljust(label.length + tab_stop - label_tabs, "\t")
end

x.each { |k, v| puts "#{tab_pad(k)}#{v}" }
# Outputs: 
#  foo                  37
#  something long       42
#  between              99
于 2016-01-15T05:31:35.010 回答
9

以前几乎没有错误,但现在您可以使用大多数 printf 语法和 % 运算符:

1.9.3-p194 :025 > " %-20s %05d" % ['hello', 12]
 => " hello                00012" 

当然你也可以使用预先计算的宽度:

1.9.3-p194 :030 > "%-#{width}s %05x" % ['hello', 12]
  => "hello          0000c" 
于 2012-10-07T22:21:05.350 回答
3

我写了一个东西

  • 自动检测列宽
  • 带空格的空格
  • 数组数组[[],[],...]或哈希数组[{},{},...]
  • 不检测对于控制台窗口来说太宽的列

    列表=[[123,“SDLKFJSLDKFJSLDKFJLSDKJF”],[123456,“ffff”],]

array_maxes

def array_maxes(lists)
  lists.reduce([]) do |maxes, list|
    list.each_with_index do |value, index|
      maxes[index] = [(maxes[index] || 0), value.to_s.length].max
    end
    maxes
  end
end

array_maxes(lists)
# => [6, 24]

puts_arrays_columns

def puts_arrays_columns(lists)
  maxes = array_maxes(hashes)
  lists.each do |list|
    list.each_with_index do |value, index|
      print " #{value.to_s.rjust(maxes[index])},"
    end
    puts
  end
end

puts_arrays_columns(lists)

# Output:
#     123, SDLKFJSLDKFJSLDKFJLSDKJF,
#  123456,                     ffff,

还有一件事

hashes = [
  { "id" => 123,    "name" => "SDLKFJSLDKFJSLDKFJLSDKJF" },
  { "id" => 123456, "name" => "ffff" },
]

hash_maxes

def hash_maxes(hashes)
  hashes.reduce({}) do |maxes, hash|
    hash.keys.each do |key|
      maxes[key] = [(maxes[key] || 0), key.to_s.length].max
      maxes[key] = [(maxes[key] || 0), hash[key].to_s.length].max
    end
    maxes
  end
end

hash_maxes(hashes)
# => {"id"=>6, "name"=>24}

puts_hashes_columns

def puts_hashes_columns(hashes)
  maxes = hash_maxes(hashes)

  return if hashes.empty?

  # Headers
  hashes.first.each do |key, value|
    print " #{key.to_s.rjust(maxes[key])},"
  end
  puts

  hashes.each do |hash|
    hash.each do |key, value|
      print " #{value.to_s.rjust(maxes[key])},"
    end
    puts
  end

end

puts_hashes_columns(hashes)

# Output:
#      id,                     name,
#     123, SDLKFJSLDKFJSLDKFJLSDKJF,
#  123456,                     ffff,

编辑:修复长度中考虑的哈希键。

hashes = [
  { id: 123,    name: "DLKFJSDLKFJSLDKFJSDF", asdfasdf: :a  },
  { id: 123456, name: "ffff",                 asdfasdf: :ab },
]

hash_maxes(hashes)
# => {:id=>6, :name=>20, :asdfasdf=>8}

想要将列列列入白名单?

hashes.map{ |h| h.slice(:id, :name) }
# => [
#  { id: 123,    name: "DLKFJSDLKFJSLDKFJSDF" },
#  { id: 123456, name: "ffff"                 },
#]
于 2014-08-04T20:56:53.273 回答
1

供将来参考以及查看或找到它的人使用...使用宝石。我建议https://github.com/wbailey/command_line_reporter

于 2015-03-17T19:05:17.743 回答
0

您通常不想使用制表符,您想使用空格并基本上设置您自己的“列”,否则您会遇到这些类型的问题。

于 2009-07-06T15:48:21.027 回答