Alineación de C ++ al imprimir cout <<

¿Hay alguna manera de alinear el texto al imprimir usando std::cout ? Estoy usando tabs, pero cuando las palabras son demasiado grandes ya no estarán alineadas.

 Sales Report for September 15, 2010 Artist Title Price Genre Disc Sale Tax Cash Merle Blue 12.99 Country 4% 12.47 1.01 13.48 Richard Music 8.49 Classical 8% 7.81 0.66 8.47 Paula Shut 8.49 Classical 8% 7.81 0.72 8.49 

La forma estándar de ISO C ++ para hacerlo es #include y utiliza manipuladores io como std::setw . Sin embargo, dicho esto, los manipuladores son un verdadero dolor para usar incluso para texto, y son casi inutilizables para formatear números (supongo que quiere que sus cantidades en dólares se alineen en el decimal, que tengan la cantidad correcta de dígitos significativos, etc. .). Incluso para las tags de texto simple, el código se verá algo así para la primera parte de su primera línea:

 // using standard iomanip facilities cout << setw(20) << "Artist" << setw(20) << "Title" << setw(8) << "Price"; // ... not going to try to write the numeric formatting... 

Si puede usar las bibliotecas de Boost , ejecute (no camine) y use la biblioteca Boost.Format en su lugar. Es totalmente compatible con los iostremas estándar, y le da toda la bondad para un fácil formateo con la cadena de formateo de impresión / Posix, pero sin perder nada de la potencia y la conveniencia de los propios iostreams. Por ejemplo, las primeras partes de sus dos primeras líneas se verían así:

 // using Boost.Format cout << format("%-20s %-20s %-8s\n") % "Artist" % "Title" % "Price"; cout << format("%-20s %-20s %8.2f\n") % "Merle" % "Blue" % 12.99; 

Ver también: ¿Qué biblioteca de CI / O debería usarse en el código de C ++?

 struct Item { std::string artist; std::string c; integer price; // in cents (as floating point is not acurate) std::string Genre; integer disc; integer sale; integer tax; }; std::cout << "Sales Report for September 15, 2010\n" << "Artist Title Price Genre Disc Sale Tax Cash\n"; FOREACH(Item loop,data) { fprintf(stdout,"%8s%8s%8.2f%7s%1s%8.2f%8.2f\n", , loop.artist , loop.title , loop.price / 100.0 , loop.Genre , loop.disc , "%" , loop.sale / 100.0 , loop.tax / 100.0); // or std::cout << std::setw(8) << loop.artist << std::setw(8) << loop.title << std::setw(8) << fixed << setprecision(2) << loop.price / 100.0 << std::setw(8) << loop.Genre << std::setw(7) << loop.disc << std::setw(1) << "%" << std::setw(8) << fixed << setprecision(2) << loop.sale / 100.0 << std::setw(8) << fixed << setprecision(2) << loop.tax / 100.0 << "\n"; // or std::cout << boost::format("%8s%8s%8.2f%7s%1s%8.2f%8.2f\n") % loop.artist % loop.title % loop.price / 100.0 % loop.Genre % loop.disc % "%" % loop.sale / 100.0 % loop.tax / 100.0; } 

Los manipuladores de IO son lo que necesitas. setw , en particular. Aquí hay un ejemplo de la página de referencia:

 // setw example #include  #include  using namespace std; int main () { cout << setw (10); cout << 77 << endl; return 0; } 

Justificar el campo a la izquierda y derecha se hace con los manipuladores left y right .

También eche un vistazo a setfill . Aquí hay un tutorial más completo sobre cómo formatear la salida C ++ con manipuladores io .

La función del manipulador setw será de ayuda aquí.

Otra forma de alinear columnas es la siguiente:

 using namespace std; cout.width(20); cout << left << "Artist"; cout.width(20); cout << left << "Title"; cout.width(10); cout << left << "Price"; ... cout.width(20); cout << left << artist; cout.width(20); cout << left << title; cout.width(10); cout << left << price; 

Debemos estimar la longitud máxima de los valores para cada columna. En este caso, los valores de la columna "Artista" no deben exceder los 20 caracteres, etc.

En el momento en que emites la primera línea,

 Artist Title Price Genre Disc Sale Tax Cash 

Para lograr la “alineación”, debe saber “de antemano” qué ancho debe tener cada columna (de lo contrario, la alineación es imposible). Una vez que conoces el ancho necesario para cada columna (hay varias maneras posibles de lograr eso dependiendo de dónde provienen tus datos), entonces la función setw mencionada en la otra respuesta te ayudará, o (más brutalmente 😉 podrías emitir cantidad de espacios extra calculados cuidadosamente (torpe, para estar seguro), etc. No recomiendo tabs de todos modos ya que no tiene control real sobre cómo el dispositivo de salida final los renderizará, en general.

Volviendo al tema central, si tiene el valor de cada columna en un vector de algún tipo, por ejemplo, puede hacer un primer pase de formateo para determinar el ancho máximo de la columna, por ejemplo (asegúrese de tener en cuenta el ancho del encabezado de la columna, también, por supuesto).

Si sus filas vienen “una por una”, y la alineación es crucial, tendrá que almacenar en caché o almacenar las filas a medida que entran (en la memoria si caben, de lo contrario en un archivo de disco que luego “rebobinará”) y volver a leer desde el principio), teniendo cuidado de mantener actualizado el vector de “anchos máximos de cada columna” a medida que las filas vienen. No se puede generar nada (¡ni siquiera los encabezados!), Si mantener la alineación es crucial, hasta que hayas visto la última fila (a menos que de alguna manera mágicamente tengas conocimiento previo del ancho de las columnas, por supuesto ;-).