Domanda

Ho scoperto questo durante l'utilizzo di ruby ??printf, ma si applica anche a printf del C.

Se si include ANSI codici colore di escape in una stringa di output, si scombina l'allineamento.

Rubino:

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 stessa linea in un programma C produce lo stesso output.

Esiste un modo per ottenere printf (o qualcos'altro) per l'uscita align e non aggiungere spazi per i caratteri non stampate?

E 'questo un bug, o c'è una ragione buona per questo?

Aggiornamento:? Dal momento che printf non può essere invocata per i dati allineare quando c'è codici ANSI e caratteri di larghezza, c'è un modo migliore pratica di allineare i dati tabulari colorate nella console in Ruby

È stato utile?

Soluzione

Non sono d'accordo con la vostra caratterizzazione di '9 spazi dopo il verde Verde'. Io uso Perl piuttosto che Ruby, ma se uso una modifica del vostro estratto conto, la stampa di un simbolo pipe dopo la stringa, ottengo:

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

Questa mostra per me che la dichiarazione printf() contava 14 caratteri della stringa, quindi anteposto 6 spazi per la produzione di 20 caratteri allineato a destra. Tuttavia, il terminale inghiottito 9 di quei personaggi, interpretandole come cambiamenti di colore. Così, l'uscita è apparso 9 caratteri più corta si voleva che. Tuttavia, il printf() non è stato stampato 9 spazi vuoti dopo il primo 'verde'.


Per quanto riguarda le migliori pratiche per l'uscita in linea (con Colorazione), penso che avrete bisogno di avere ogni campo di dimensioni-e-allineati circondato da semplice '% s' campi che si occupano della Colorazione:

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;

Dove, ovviamente, le variabili co_XXXX (costanti?) Contengono le sequenze di escape per passare al colore di nome (e co_plain potrebbe essere migliore come co_black). Se si scopre che non è necessario Colorazione su qualche campo, è possibile utilizzare la stringa vuota al posto delle variabili co_XXXX (o chiamare co_empty).

Altri suggerimenti

Non è un bug: non c'è modo rubino dovrebbe sapere (almeno entro printf, sarebbe una storia diversa per qualcosa come maledizioni) che il suo stdout sta per un terminale che capisce VT100 sequenze di escape

.

Se non sei la regolazione dei colori di sfondo, qualcosa di simile potrebbe essere un'idea migliore:

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

campo printf identificatori larghezza non sono utili per allineare i dati tabulari, elementi di interfaccia, ecc A parte la questione dei caratteri di controllo, che è già stato scoperto, ci sono anche senza spaziatura e doppia larghezza caratteri che il programma avrà a che fare con se non si vuole le cose limite di vecchie codifiche (che molti utenti considerano deprecato).

Se ti ostini a usare printf in questo modo, probabilmente bisogno di fare qualcosa di simile:

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

dove bytestopad(s,n) è una funzione di scrivere che calcola come intero quanti byte totali (stringa inclusa imbottitura spazi) ai risultati nella s stringa occupare colonne terminali n. Ciò comporterebbe parsing fughe e processare caratteri multibyte e utilizzando un impianto (come la funzione wcwidth POSIX) di ricercare quante colonne terminali ciascuno prende. Si noti l'uso di * al posto di un campo costante larghezza nella stringa di formato printf. Questo permette di passare un argomento int per printf per larghezze di campo di runtime-variabile.

Vorrei estrarre le sequenze di escape dal testo effettivo per evitare l'intera questione.

# 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");

Dal sequenze di escape ANSI non fanno parte di una Ruby o C non pensa che hanno bisogno per il trattamento di questi caratteri speciali, ed è giusto così.

Se avete intenzione di fare un sacco di roba di colore Terminal, allora si dovrebbe guardare in maledizioni e ncurses che forniscono funzioni per fare il colore cambia il lavoro per molti diversi tipi di terminali. Forniscono anche molto molto di più funzionalità, come finestre testuale, tasti funzione, e talvolta anche l'interazione del mouse.

Ecco una soluzione mi è venuta di recente. Questo consente di utilizzare color("my string", :red) in un comunicato printf. Mi piace usare la stessa stringa di formattazione per le intestazioni ei dati - A SECCO. Ciò lo rende possibile. Inoltre, io uso il gioiello arcobaleno per generare i codici colore; non è perfetto, ma ottiene il lavoro fatto. L'hash CPAD contiene due valori per ciascun colore, corrispondente al padding sinistra e destra rispettivamente. Naturalmente, questa soluzione dovrebbe essere esteso per facilitare altri colori e modificatori come il grassetto e sottolineato.

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

Esempio:

puts "%-10s   %-10s   %-10s   %-10s" % [
  color('apple',  :red),
  color('pear',   :green),
  color('banana', :yellow)
  color('kiwi',   :default)
]
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top