2009-07-06 15 views
47

Estoy generando una secuencia de comandos que está enviando información a la consola. La información es algún tipo de estadística con un valor. Tanto como un hash.Agradable formato de salida a la consola, especificando el número de pestañas

De modo que un nombre de valor puede tener 8 caracteres de largo y otro es 3. cuando estoy realizando un bucle para generar la información con dos \ t algunas de las columnas no están alineadas correctamente.

Así, por ejemplo, la salida podría ser como tal:

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

Quiero que todos los valores alineados correctamente. En este momento estoy haciendo esto:

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

¿Cómo podría decir que para los nombres largos, para usar solo una pestaña? ¿O hay otra solución?

Respuesta

22

Por lo general, hay un %10s tipo de esquema printf que formatea muy bien.
Sin embargo, no he usado rubí en absoluto, así que debes comprobarlo.


Sí, hay printf con formato.
El ejemplo de arriba debe alinearse a la derecha en un espacio de 10 caracteres.
Puede formatear según su campo más ancho en la columna.

printf ([puerto], formato, arg ...)

Prints argumentos formateados según el formato como sprintf. Si el primer argumento es la instancia del IO o su subclase, imprima redirigido a ese objeto. el valor predeterminado es el valor de $ stdout.

+1

Hay un printf y sprintf que utilizan los argumentos C para formatear una cadena. Son métodos en Kernal (efectivamente integrados). Ver http://www.ruby-doc.org/core/classes/Kernel.html#M005962. –

+2

printf ("% - 10s% 10s", args) hizo el truco ... ¡Muchas gracias! – predhme

+3

recordar [printf (* args)] (http://apidock.com/ruby/Kernel/printf) tiene una [implementación en la cadena #] (http://ruby-doc.org/docs/ProgrammingRuby/html/ ref_c_string.html # String._pc):%: '"% s% 10s "% [value_name, value]' se ve muy bien. De todos modos, ¡no estropees tu código con grandes términos de esto! – abstraktor

0

Normalmente no desea utilizar pestañas, desea utilizar espacios y esencialmente configurar sus "columnas" usted mismo o de lo contrario se encuentra con este tipo de problemas.

49

siempre y cuando sepas la longitud máxima a ser no más de 20 caracteres:

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

Si desea hacerlo más dinámico, algo como esto debería funcionar muy bien:

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

¡Muy buen truco! ¡Lo guardaré para el futuro! – predhme

+0

Utilicé su código y lo sustituí por 'ENV' para 'data_hash', inmediatamente útil. ¡Gracias! –

10

No se algunos errores antes, pero ahora puede usar la mayoría de la sintaxis de printf con operador%:

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

De curso e puede utilizar el ancho calculado previamente también:

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

escribí una cosa

  • detecta automáticamente el ancho de las columnas
  • Espacios con espacios
  • matriz de matrices [[],[],...] o gama de valores hash [{},{},...]
  • No detecta columnas demasiado anchas para la ventana de la consola

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

y otro 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, 

Editar: claves hash Corrige considerados en la longitud.

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

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

¿Quieres incluir las columnas en la lista blanca?

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

cadena tiene un built-in ljust exactamente esto:

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 

O, si quieres pestañas, se puede hacer un poco de matemáticas (suponiendo ancho de pantalla de la ficha de 8) y escribir un corto función de visualización:

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 
Cuestiones relacionadas