2009-07-06 8 views
47

Generuję skrypt, który wysyła informacje do konsoli. Informacja jest rodzajem statystyki o wartości. Tak jak hash.Ładnie formatujące dane wyjściowe do konsoli, określające liczbę zakładek

Tak więc nazwa jednej wartości może składać się z 8 znaków, a inna z 3., gdy przechodzę do wyjścia, wypisując informacje z dwoma \ t niektóre kolumny nie są poprawnie wyrównane.

Tak na przykład wyjście może być jako takie:

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

Chcę wszystkie wartości ustawieni prawidłowo. Właśnie teraz robię to:

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

Jak mogę powiedzieć o długich nazwach, używać tylko jednej zakładki? Czy istnieje inne rozwiązanie?

Odpowiedz

22

Zazwyczaj jest to %10s rodzaj schematu printf, który ładnie się formatuje.
Jednak nie użyłem ruby ​​w ogóle, więc musisz to sprawdzić.


Tak, istnieje printf z formatowaniem.
Powyższy przykład powinien być wyrównany do 10 znaków.
Możesz formatować na podstawie najszerszego pola w kolumnie. (Format [port] arg ...)

printf

Wydruki argumentów sformatowanych zgodnie z formatem jak sprintf. Jeśli pierwszym argumentem jest instancja IO lub jej podklasy, drukuj przekierowany do tego obiektu. wartość domyślna to wartość $ stdout.

+1

Istnieje printf i sprintf, które używają argumentów C do sformatowania ciągu znaków. Są to metody na Kernalu (skutecznie wbudowane). Zobacz http://www.ruby-doc.org/core/classes/Kernel.html#M005962. –

+2

printf ("% - 10%% 10s", args) załatwił sprawę ... Wielkie dzięki! – predhme

+3

pamiętaj, że [printf (* args)] (http://apidock.com/ruby/Kernel/printf) ma [implementację na łańcuchu #] (http://ruby-doc.org/docs/ProgrammingRuby/html/ ref_c_string.html # String._pc):%: '"% s% 10s "% [value_name, value]' wygląda świetnie. W każdym razie, nie niszczyć kodu z dużymi warunkami tego! – abstraktor

0

Zazwyczaj nie chcesz używać kart, chcesz używać spacji i zasadniczo konfigurować swoje "kolumny" samodzielnie lub napotkasz na tego typu problemy.

49

warunkiem wiesz maksymalną długość być nie więcej niż 20 znaków:

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

Jeśli chcesz uczynić go bardziej dynamiczny, coś jak to powinno działać ładnie:

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

Bardzo dobra sztuczka! Zatrzymam to na przyszłość! – predhme

+0

Użyłem twojego kodu i podstawiłem 'ENV' dla 'data_hash', natychmiast użyteczne - Dzięki! –

10

Nie było kilka błędów wcześniej, ale teraz możesz użyć większości składni printf z% operator:

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

Z cours e można użyć szerokość obliczane wstępnie też:

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

pisałem coś

  • Automatycznie wykrywa kolumna szerokości
  • Spaces ze spacjami
  • tablicy tablic [[],[],...] lub tablicę skrótów [{},{},...]
  • Nie wykrywa zbyt szerokich kolumn dla okna konsoli

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

i innym rzecz

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: Poprawki klawisze skrótu uwzględnione w długości.

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

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

Chcesz umieścić na białej liście kolumny kolumn?

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

String posiada wbudowany ljust za dokładnie to:

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 

Albo, jeśli chcesz zakładek, można zrobić trochę matematyki (zakładając szerokość wyświetlania Zakładka z 8) i napisać krótki funkcja wyświetlania:

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 
Powiązane problemy