¿Cómo puedo alinear texto en columnas usando Console.WriteLine?

78

Tengo una especie de visualización de columna, pero las dos columnas finales parecen no alinearse correctamente. Este es el código que tengo en este momento:

Console.WriteLine("Customer name    " 
    + "sales          " 
    + "fee to be paid    " 
    + "70% value       " 
    + "30% value");
for (int DisplayPos = 0; DisplayPos < LineNum; DisplayPos = DisplayPos + 1)
{
    seventy_percent_value = ((fee_payable[DisplayPos] / 10.0) * 7);
    thirty_percent_value = ((fee_payable[DisplayPos] / 10.0) * 3);          
    Console.WriteLine(customer[DisplayPos] + "         " 
        + sales_figures[DisplayPos] + "               " 
        + fee_payable[DisplayPos] + "           " 
        + seventy_percent_value + "           " 
        + thirty_percent_value);
}

Soy un programador novato, por lo que es posible que no entienda todos los consejos que se dan, pero si tiene algún consejo, se lo agradecería mucho.

Stephen Smith
fuente
1
Consulte aquí para obtener una versión más generalizada de esta pregunta. También vale la pena echarle un vistazo a las respuestas.
Adam Glauser

Respuestas:

13

En lugar de intentar alinear manualmente el texto en columnas con cadenas arbitrarias de espacios, debe incrustar pestañas reales (la \tsecuencia de escape) en cada cadena de salida:

Console.WriteLine("Customer name" + "\t"
    + "sales" + "\t" 
    + "fee to be paid" + "\t" 
    + "70% value" + "\t" 
    + "30% value");
for (int DisplayPos = 0; DisplayPos < LineNum; DisplayPos++)
{
    seventy_percent_value = ((fee_payable[DisplayPos] / 10.0) * 7);
    thirty_percent_value = ((fee_payable[DisplayPos] / 10.0) * 3);          
    Console.WriteLine(customer[DisplayPos] + "\t" 
        + sales_figures[DisplayPos] + "\t" 
        + fee_payable + "\t\t"
        + seventy_percent_value + "\t\t" 
        + thirty_percent_value);
}
Cody Grey
fuente
37
Las pestañas solo funcionarán bien si todos sus datos tienen una longitud similar. Si tiene datos de diferente longitud, debe usar la respuesta royas con cadenas de formato.
Tim
3
Sí, la suya es una respuesta mucho mejor. Lo voté a favor tan pronto como lo vi, pero dejé el mío solo en caso de que el enfoque más simple fuera más efectivo. Aunque no estoy seguro de por qué se aceptó el mío ... :-)
Cody Gray
1
Y no se olvide de string.PadRight () y string.PadLeft ()
nhershy
La respuesta de roya no es útil si está tratando de alinear el texto con un ancho de fuente variable. Creo que debe usar una combinación de relleno con pestañas como en esta respuesta .
sean
316

Prueba esto

Console.WriteLine("{0,10}{1,10}{2,10}{3,10}{4,10}",
  customer[DisplayPos],
  sales_figures[DisplayPos],
  fee_payable[DisplayPos], 
  seventy_percent_value,
  thirty_percent_value);

donde el primer número dentro de las llaves es el índice y el segundo es la alineación. El signo del segundo número indica si la cuerda debe estar alineada a la izquierda oa la derecha. Utilice números negativos para la alineación a la izquierda.

O mire http://msdn.microsoft.com/en-us/library/aa331875(v=vs.71).aspx

royas
fuente
18
en realidad no es necesario pasar el método string.format. En otras palabras, será lo mismo que hacer:Console.WriteLine("{0,10}{1,10}{2,10}{3,10}{4,10}", customer[DisplayPos], sales_figures[DisplayPos], fee_payable[DisplayPos], seventy_percent_value, thirty_percent_value);
Tono Nam
63

Solo para agregar a la respuesta de roya. En c # 6.0 ahora puede usar la interpolación de cadenas:

Console.WriteLine($"{customer[DisplayPos],10}" +
                  $"{salesFigures[DisplayPos],10}" +
                  $"{feePayable[DisplayPos],10}" +
                  $"{seventyPercentValue,10}" +
                  $"{thirtyPercentValue,10}");

En realidad, esto puede ser una línea sin todos los dólares adicionales, solo creo que hace que sea un poco más fácil de leer así.

Y también puede usar una importación estática en System.Console, lo que le permite hacer esto:

using static System.Console;

WriteLine(/* write stuff */);
Daniel Hakimi
fuente
5
msdn.microsoft.com/en-us/library/txafckwd(v=vs.110).aspx tiene documentación sobre la "alineación". ¡Muy útil!
Frison Alexander
4
Para Alinear a la izquierda, entonces sólo tiene que utilizar un número negativo como esto: $"{thirtyPercentValue,-10}".
stomtech
7

Lo sé, un hilo muy antiguo, pero la solución propuesta no era completamente automática cuando hay cadenas más largas.

Por lo tanto, creé un pequeño método auxiliar que lo hace completamente automático. Simplemente pase una lista de matriz de cadenas donde cada matriz representa una línea y cada elemento de la matriz, bueno, un elemento de la línea.

El método se puede utilizar así:

var lines = new List<string[]>();
lines.Add(new[] { "What", "Before", "After"});
lines.Add(new[] { "Name:", name1, name2});
lines.Add(new[] { "City:", city1, city2});
lines.Add(new[] { "Zip:", zip1, zip2});
lines.Add(new[] { "Street:", street1, street2});
var output = ConsoleUtility.PadElementsInLines(lines, 3);

El método de ayuda es el siguiente:

public static class ConsoleUtility
{
    /// <summary>
    /// Converts a List of string arrays to a string where each element in each line is correctly padded.
    /// Make sure that each array contains the same amount of elements!
    /// - Example without:
    /// Title Name Street
    /// Mr. Roman Sesamstreet
    /// Mrs. Claudia Abbey Road
    /// - Example with:
    /// Title   Name      Street
    /// Mr.     Roman     Sesamstreet
    /// Mrs.    Claudia   Abbey Road
    /// <param name="lines">List lines, where each line is an array of elements for that line.</param>
    /// <param name="padding">Additional padding between each element (default = 1)</param>
    /// </summary>
    public static string PadElementsInLines(List<string[]> lines, int padding = 1)
    {
        // Calculate maximum numbers for each element accross all lines
        var numElements = lines[0].Length;
        var maxValues = new int[numElements];
        for (int i = 0; i < numElements; i++)
        {
            maxValues[i] = lines.Max(x => x[i].Length) + padding;
        }
        var sb = new StringBuilder();
        // Build the output
        bool isFirst = true;
        foreach (var line in lines)
        {
            if (!isFirst)
            {
                sb.AppendLine();
            }
            isFirst = false;
            for (int i = 0; i < line.Length; i++)
            {
                var value = line[i];
                // Append the value with padding of the maximum length of any value for this element
                sb.Append(value.PadRight(maxValues[i]));
            }
        }
        return sb.ToString();
    }
}

Espero que esto ayude a alguien. La fuente es de una publicación en mi blog aquí: http://dev.flauschig.ch/wordpress/?p=387

Roemer
fuente
Ésta es la respuesta más precisa. No obstante, he mejorado su método para esa última línea que no siempre tiene todas las líneas declaradas: pastebin.com/CVkavHgy
David Diez
Si usa Console.Write para imprimir "salida", puede deshacerse de esa isFirstparte. Solo haz lo sb.AppendLine();al final del foreach.
tomwaitforitmy
2

Puede usar pestañas en lugar de espacios entre columnas y / o establecer el tamaño máximo para una columna en cadenas de formato ...

LaGrandMere
fuente
2

Hay varios paquetes de NuGet que pueden ayudar con el formato. En algunos casos, las capacidades de string.Formatson suficientes, pero es posible que desee cambiar automáticamente el tamaño de las columnas según el contenido, al menos.

ConsoleTableExt

ConsoleTableExt es una biblioteca simple que permite formatear tablas, incluidas tablas sin líneas de cuadrícula. (Un paquete ConsoleTables más popular no parece admitir tablas sin bordes ). A continuación, se muestra un ejemplo de cómo dar formato a una lista de objetos con columnas de tamaño según su contenido:

ConsoleTableBuilder
    .From(orders
        .Select(o => new object[] {
            o.CustomerName,
            o.Sales,
            o.Fee,
            o.Value70,
            o.Value30
        })
        .ToList())
    .WithColumn(
        "Customer",
        "Sales",
        "Fee",
        "70% value",
        "30% value")
    .WithFormat(ConsoleTableBuilderFormat.Minimal)
    .WithOptions(new ConsoleTableBuilderOption { DividerString = "" })
    .ExportAndWriteLine();

CsConsoleFormat

Si necesita más funciones que eso, cualquier formateo de consola se puede lograr con CsConsoleFormat . † Por ejemplo, aquí se formatea una lista de objetos como una cuadrícula con un ancho de columna fijo de 10, como en las otras respuestas usando string.Format:

ConsoleRenderer.RenderDocument(
    new Document { Color = ConsoleColor.Gray }
        .AddChildren(
            new Grid { Stroke = LineThickness.None }
                .AddColumns(10, 10, 10, 10, 10)
                .AddChildren(
                    new Div("Customer"),
                    new Div("Sales"),
                    new Div("Fee"),
                    new Div("70% value"),
                    new Div("30% value"),
                    orders.Select(o => new object[] {
                        new Div().AddChildren(o.CustomerName),
                        new Div().AddChildren(o.Sales),
                        new Div().AddChildren(o.Fee),
                        new Div().AddChildren(o.Value70),
                        new Div().AddChildren(o.Value30)
                    })
                )
        ));

Puede parecer más complicado que puro string.Format, pero ahora se puede personalizar. Por ejemplo:

  • Si desea ajustar automáticamente el tamaño de las columnas según el contenido, reemplácelo AddColumns(10, 10, 10, 10, 10)con AddColumns(-1, -1, -1, -1, -1)( -1es un acceso directo a GridLength.Auto, tiene más opciones de tamaño, incluido el porcentaje del ancho de la ventana de la consola).

  • Si desea alinear las columnas numéricas a la derecha, agréguelas { Align = Right }al inicializador de una celda.

  • Si desea colorear una columna, agréguela { Color = Yellow }al inicializador de una celda.

  • Puede cambiar estilos de borde y más.

† CsConsoleFormat fue desarrollado por mí.

Athari
fuente
1

Realmente me gustan esas bibliotecas mencionadas aquí, pero tuve una idea que podría ser más simple que simplemente rellenar o hacer toneladas de manipulaciones de cuerdas.

Puede configurar manualmente el cursor utilizando la longitud máxima de cadena de sus datos. Aquí hay un código para hacerse una idea (no probado):

var column1[] = {"test", "longer test", "etc"}
var column2[] = {"data", "more data", "etc"}
var offset = strings.OrderByDescending(s => s.Length).First().Length;
for (var i = 0; i < column.Length; i++) {
    Console.Write(column[i]);
    Console.CursorLeft = offset + 1;
    Console.WriteLine(column2[i]);
}

podría extrapolar fácilmente si tiene más filas.

Sauleil
fuente
0

Haz algo de relleno, es decir

          public static void prn(string fname, string fvalue)
            {
                string outstring = fname.PadRight(20)  +"\t\t  " + fvalue;
                Console.WriteLine(outstring);

            }

Esto funcionó bien, al menos para mí.

מלך המשיח
fuente