2009-07-06 11 views
47

Sto generando uno script che sta trasmettendo informazioni alla console. L'informazione è una sorta di statistica con un valore. Così simile a un hash.Buona formattazione dell'output per la console, specificando il numero di schede

Quindi il nome di un valore può essere lungo 8 caratteri e un altro è 3. quando eseguo il ciclo di output delle informazioni con due \ t alcune colonne non sono allineate correttamente.

Così, per esempio l'uscita potrebbe essere in quanto tale:

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

Voglio tutti i valori allineati correttamente. In questo momento sto facendo questo:

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

Come potrei dire per i nomi lunghi, per usare solo una scheda? O c'è un'altra soluzione?

risposta

22

Di solito c'è uno %10s tipo di schema printf che si adatta bene.
Tuttavia, non ho usato il rubino, quindi è necessario verificarlo.


Sì, c'è una stampa con la formattazione.
L'esempio sopra riportato dovrebbe essere allineato in uno spazio di 10 caratteri.
È possibile formattare in base al campo più largo nella colonna. (Formato [porta,], arg ...)

printf

Prints argomenti formattati in base al formato, come sprintf. Se il primo argomento è l'istanza dell'IO o della sua sottoclasse, stampa reindirizzato a quell'oggetto. il valore predefinito è $ stdout.

+1

C'è un printf e uno sprint che utilizzano gli argomenti C per formattare una stringa. Sono metodi su Kernal (efficacemente integrato). Vedi http://www.ruby-doc.org/core/classes/Kernel.html#M005962. –

+2

printf ("% - 10s% 10s", args) ha fatto il trucco ... Grazie mille! – predhme

+3

ricorda [printf (* args)] (http://apidock.com/ruby/Kernel/printf) ha una [implementazione su string #] (http://ruby-doc.org/docs/ProgrammingRuby/html/ ref_c_string.html # String._pc):%: '"% s% 10s "% [value_name, value]' sembra fantastico. Ad ogni modo, non sfigurare il tuo codice con grandi termini di questo! – abstraktor

0

In genere non si desidera utilizzare le schede, che si desidera utilizzare spazi e essenzialmente configurare il "colonne" la vostra auto, altrimenti si esegue in questi tipi di problemi.

49

condizione di sapere la lunghezza massima di essere non più di 20 caratteri:

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

Se si vuole rendere più dinamico, qualcosa di simile dovrebbe funzionare bene:

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

Trucco molto bello! Lo terrò per il futuro! – predhme

+0

Ho usato il tuo codice e sostituito 'ENV' per 'data_hash', immediatamente utile - Grazie !! –

10

C'era pochi bug in esso prima, ma ora è possibile utilizzare la maggior parte della sintassi di printf con% operatore:

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

di cours e si può utilizzare la larghezza precalcolata troppo:

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

ho scritto una cosa

  • Rileva automaticamente la larghezza delle colonne
  • gli ambienti con spazi
  • array di array [[],[],...] o array di hash [{},{},...]
  • Non rileva colonne troppo larghe per la finestra della console

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

e un altro cosa

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: Correzioni chiavi hash considerati nella lunghezza.

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

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

Vuoi colonne colonne whitelist?

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

String ha un built-in ljust proprio per questo:

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 

Oppure, se si desidera che le schede, si può fare un po 'di matematica (supponendo larghezza di visualizzazione scheda di 8) e scrivere una breve funzione display:

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