Pregunta

Me descubrió esto durante el uso de printf rubí, pero también se aplica a printf de C.

Si se incluyen los códigos de color de escape ANSI en una cadena de salida, ya que se rompe la alineación.

Ruby:

ruby-1.9.2-head > printf "%20s\n%20s\n", "\033[32mGreen\033[0m", "Green"
      Green          # 6 spaces to the left of this one
               Green # correctly padded to 20 chars
 => nil

La misma línea en un programa de C produce la misma salida.

¿Hay alguna forma de conseguir printf (o algo más) a la salida de alineación y no añadir espacios para caracteres no impresos?

¿Es esto es un error, o hay una buena razón para ello?

Actualización:? Desde printf no se puede confiar en los datos align cuando hay códigos ANSI y caracteres de ancho, hay una mejor manera práctica de alinear los datos tabulares de color en la consola de rubí

¿Fue útil?

Solución

No estoy de acuerdo con su caracterización de '9 espacios después del verde verde'. Yo uso de Perl en lugar de Ruby, pero si uso una modificación de su estado de cuenta, se imprime un símbolo de canalización después de la cadena, me sale:

perl -e 'printf "%20s|\n%20s|\n", "\033[32mGreen\033[0m", "Green";'
      Green|
               Green|

Esto demuestra a mí que la declaración printf() contaba 14 caracteres en la cadena, por lo que antepone 6 espacios para producir 20 caracteres alineados a la derecha. Sin embargo, el terminal se tragó 9 de esos personajes, interpretándolos como cambios de color. Por lo tanto, la salida apareció 9 caracteres más corta de lo que quería. Sin embargo, el printf() no se imprimió 9 espacios en blanco después de la primera 'verde'.


En cuanto a las mejores prácticas para la producción alineados (con colourization), creo que tendrá que tener cada campo de tamaño y alineados rodeado por simple '% s' campos que se ocupan de la colorización:

printf "%s%20.20s%s|%s%-10d%s|%s%12.12s%s|\n",
       co_green, column_1_data, co_plain,
       co_blue,  column_2_data, co_plain,
       co_red,   column_3_data, co_plain;

Cuando, obviamente, las variables co_XXXX (constantes?) Contienen las secuencias de escape para cambiar al color con nombre (y co_plain podría ser mejor que co_black). Si resulta que no es necesario colourization en algún campo, puede utilizar la cadena vacía en lugar de las variables co_XXXX (o llamarlo co_empty).

Otros consejos

No es un error: no hay manera de rubí debe saber (al menos dentro de printf, sería una historia diferente para algo así como maldiciones) que su salida estándar va a un terminal que comprende VT100 secuencias de escape

.

Si usted no está ajustando los colores de fondo, algo como esto podría ser una mejor idea:

GREEN = "\033[32m"
NORMAL = "\033[0m"
printf "%s%20s%s\n", GREEN, "Green", NORMAL

especificadores anchura del campo printf no son útiles para la alineación de los datos tabulares, elementos de la interfaz, etc. Aparte de la cuestión de los caracteres de control, que ya ha descubierto, también hay Sin espacio y caracteres que su programa tendrá que lidiar con doble ancho si no quiere cosas de límite para la codificación de caracteres legado (que muchos usuarios consideran que se use).

Si usted insiste en el uso de printf esta manera, es probable que tenga que hacer algo como:

printf("%*s\n%*s\n", bytestopad("\033[32mGreen\033[0m", 20), "\033[32mGreen\033[0m", bytestopad("Green", 20), "Green");

donde bytestopad(s,n) es una función que escribe que calcula cómo se necesitan muchos total de bytes (cadena de caracteres más espacios de relleno) para dar como resultado la cadena s ocupar columnas terminales n. Esto implicaría analizar los escapes y el procesamiento de caracteres de varios bytes y el uso de una instalación (como la función wcwidth POSIX) para buscar el número de columnas terminales cada toma. Observe el uso de * en lugar de un campo constante anchura en la cadena de formato printf. Esto le permite pasar un argumento a int printf para anchos de campo de tiempo de ejecución variable.

Me separar las secuencias de escape de texto real para evitar todo el asunto.

# in Ruby
printf "%s%20s\n%s%20s\n", "\033[32m", "Green", "\033[0m", "Green"

o

/* In C */
printf("%s%20s\n%s%20s\n", "\033[32m", "Green", "\033[0m", "Green");

Como las secuencias de escape ANSI no son parte de cualquiera de Ruby o C ni piensa que necesitan para tratar estos caracteres especiales, y con razón.

Si usted va a estar haciendo un montón de cosas de color del terminal entonces usted debe buscar en maldiciones y ncurses que proporcionan funciones para hacer cambios de color que el trabajo para muchos tipos diferentes de terminales. También proporcionan mucho más funcionalidad, como ventanas a base de texto, teclas de función y, a veces, incluso la interacción del ratón.

Esta es una solución que se me ocurrió recientemente. Esto le permite utilizar color("my string", :red) en un comunicado printf. Me gusta usar el mismo formato de cadenas para las cabeceras y los datos - SECO. Esto hace que sea posible. Además, utilizo la gema arco iris para generar los códigos de color; que no es perfecto, pero hace el trabajo. El hash CPAD contiene dos valores para cada color, que corresponde al relleno de izquierda y derecha, respectivamente. Naturalmente, esta solución debe extenderse a facilitar otros colores y modificadores tales como negrita y subrayado.

CPAD = {
  :default => [0, 2],
  :green   => [0, 3],
  :yellow  => [0, 2],
  :red     => [0, 1],
}

def color(text, color)
  "%*s%s%*s" % [CPAD[color][0], '', text.color(color), CPAD[color][1], '']
end

Ejemplo:

puts "%-10s   %-10s   %-10s   %-10s" % [
  color('apple',  :red),
  color('pear',   :green),
  color('banana', :yellow)
  color('kiwi',   :default)
]
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top