web-dev-qa-db-fra.com

Formatage agréable de la sortie vers la console, en spécifiant le nombre d'onglets

Je génère un script qui génère des informations sur la console. L'information est une sorte de statistique avec une valeur. Un peu comme un hachage.

Ainsi, le nom d'une valeur peut comporter 8 caractères et un autre 3. Lorsque je passe en boucle la sortie des informations avec deux\t certaines des colonnes ne sont pas alignées correctement.

Ainsi, par exemple, la sortie peut être en tant que telle:

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

Je veux que toutes les valeurs soient alignées correctement. En ce moment, je fais ceci:

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

Comment pourrais-je dire pour les noms longs, de n'utiliser qu'un seul onglet? Ou existe-t-il une autre solution?

53
user130532

Il y a généralement un %10s type de schéma printf qui formate bien.
Cependant, je n'ai pas utilisé Ruby du tout, donc vous devez vérifier cela.


Oui, il y a printf avec formatage.
L'exemple ci-dessus doit s'aligner à droite dans un espace de 10 caractères.
Vous pouvez formater en fonction de votre champ le plus large dans la colonne.

printf ([port,] format, arg ...)

Imprime des arguments formatés selon le format comme sprintf. Si le premier argument est l'instance de IO ou sa sous-classe, print redirigé vers cet objet. La valeur par défaut est la valeur de $ stdout.

23
nik

Pourvu que la longueur maximale ne dépasse pas 20 caractères:

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

Si vous voulez le rendre plus dynamique, quelque chose comme ça devrait bien fonctionner:

longest_key = data_hash.keys.max_by(&:length)
data_hash.each do |key, value|
  printf "%-#{longest_key.length}s %s\n", key, value
end
55
Lars Haugseth

La chaîne a un ljust intégré pour exactement cela:

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

Ou, si vous voulez des onglets, vous pouvez faire un peu de calcul (en supposant une largeur d'affichage de 8 onglets) et écrire une courte fonction d'affichage:

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
14
Kyle VanderBeek

Il y avait quelques bogues auparavant, mais maintenant vous pouvez utiliser la plupart de la syntaxe printf avec l'opérateur%:

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

Bien sûr, vous pouvez également utiliser la largeur précalculée:

1.9.3-p194 :030 > "%-#{width}s %05x" % ['hello', 12]
  => "hello          0000c" 
10
sergeych

J'ai écrit une chose

  • Détecte automatiquement les largeurs de colonne
  • Des espaces avec des espaces
  • Tableau de tableaux [[],[],...] ou tableau de hachages [{},{},...]
  • Ne détecte pas les colonnes trop larges pour la fenêtre de la console

    lists = [[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,

et autre chose

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,

Edit: corrige les clés de hachage considérées dans la longueur.

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

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

Vous voulez ajouter des colonnes aux colonnes?

hashes.map{ |h| h.slice(:id, :name) }
# => [
#  { id: 123,    name: "DLKFJSDLKFJSLDKFJSDF" },
#  { id: 123456, name: "ffff"                 },
#]
3
Nate

Pour référence future et les personnes qui regardent cela ou le trouvent ... Utilisez un joyau. Je suggère https://github.com/wbailey/command_line_reporter

1
Brett Hardin

Vous ne voulez généralement pas utiliser d'onglets, vous voulez utiliser des espaces et configurer vous-même vos "colonnes", sinon vous rencontrez ces types de problèmes.

0
ThaDon