ascii-table

repository·master·Indexed 40 days ago

https://github.com/freva/ascii-table

A Java library for creating and customizing ASCII tables for console output. Version 1.13.0 supports mapping collections and streams to tables, custom column alignments, width constraints, and various overflow behaviors. It includes a builder for advanced customization, support for footers, and multiple predefined border styles such as BASIC_ASCII and FANCY_ASCII.

Tokens
5K
Snippets
12
Records
13
Agent score
50%

What's inside ascii-table

  1. Create a custom border style

    master

    To create a custom border style, you must provide a Character[] of length 29. To understand which index controls which part of the table, you can use a diagnostic string of unique characters.

    Use the following pattern to map the 29 indices to their visual locations in the table structure:

    // Diagnostic tool to see which index maps to which table part
    Character[] borderStyles = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123".chars()
        .mapToObj(c -> (char)c)
        .toArray(Character[]::new);
    
    // Use this array in AsciiTable.getTable() to see the mapping in the output

    Template for a custom style array:

    public static final Character[] CUSTOM = {
        null, // Index 0 (A)
        null, // Index 1 (B)
        null, // Index 2 (C)
        null, // Index 3 (D)
        null, // Index 4 (E)
        null, // Index 5 (F)
        null, // Index 6 (G)
        null, // Index 7 (H)
        null, // Index 8 (I)
        null, // Index 9 (J)
        null, // Index 10 (K)
        null, // Index 11 (L)
        null, // Index 12 (M)
        null, // Index 13 (N)
        null, // Index 14 (O)
        null, // Index 15 (P)
        null, // Index 16 (Q)
        null, // Index 17 (R)
        null, // Index 18 (S)
        null, // Index 19 (T)
        null, // Index 20 (U)
        null, // Index 21 (V)
        null, // Index 22 (W)
        null, // Index 23 (X)
        null, // Index 24 (Y)
        null, // Index 25 (Z)
        null, // Index 26 (1)
        null, // Index 27 (2)
        null  // Index 28 (3)
    };
  2. Install ascii-table via Maven or Gradle

    master

    To use ascii-table in your Java project, add the following dependency to your build configuration.

    <dependency>
      <groupId>com.github.freva</groupId>
      <artifactId>ascii-table</artifactId>
      <version>1.13.0</version>
    </dependency>
    compile 'com.github.freva:ascii-table:1.13.0'
  3. Create a table from a Collection of objects

    master

    You can map a List of objects to an ASCII table by defining a list of Column objects. Each Column uses a lambda expression to extract the data for that specific field.

    List<Planet> planets = Arrays.asList(
            new Planet(1, "Mercury", 0.382, 0.06, "minimal"),
            new Planet(2, "Venus", 0.949, 0.82, "Carbon dioxide, Nitrogen"),
            new Planet(3, "Earth", 1.0, 1.0, "Nitrogen, Oxygen, Argon"),
            new Planet(4, "Mars", 0.532, 0.11, "Carbon dioxide, Nitrogen, Argon"));
    
    System.out.println(AsciiTable.getTable(planets, Arrays.asList(
            new Column().with(planet -> Integer.toString(planet.num)),
            new Column().header("Name").with(planet -> planet.name),
            new Column().header("Diameter").with(planet -> String.format("%.03f", planet.diameter)),
            new Column().header("Mass").with(planet -> String.format("%.02f", planet.mass)),
            new Column().header("Atmosphere").with(planet -> planet.atmosphere))));
  4. Create a basic ASCII table from arrays

    master

    For simple use cases, you can generate a table directly from a 2D array of Strings for data and a 1D array of Strings for headers using AsciiTable.getTable(headers, data).

    String[] headers = {"", "Name", "Diameter", "Mass", "Atmosphere"};
    String[][] data = {
            {"1", "Mercury", "0.382", "0.06", "minimal"},
            {"2", "Venus", "0.949", "0.82", "Carbon dioxide, Nitrogen"},
            {"3", "Earth", "1.000", "1.00", "Nitrogen, Oxygen, Argon"},
            {"4", "Mars", "0.532", "0.11", "Carbon dioxide, Nitrogen, Argon"}};
    
    System.out.println(AsciiTable.getTable(headers, data));
  5. Set maximum table width using the Builder

    master

    To constrain the total width of the entire table, use the AsciiTable.builder() pattern. This is useful for ensuring the table fits within a specific terminal width.

    System.out.println(AsciiTable.builder().data(planets, Arrays.asList(
                new Column().with(planet -> Integer.toString(planet.num)),
                new Column().minWidth(10).with(planet -> planet.name),
                new Column().with(planet -> String.format("%.03f", planet.diameter)),
                new Column().with(planet -> String.format("%.02f", planet.mass)),
                new Column().maxWidth(12).with(planet -> planet.atmosphere)))
            .maxTableWidth(50)
            .asString());
  6. Configure border styles for AsciiTable

    master

    You can customize the visual appearance of your table by providing a Character[] array to the AsciiTable.getTable() method. The array must be exactly 29 characters long. Each index in the array corresponds to a specific structural element of the table (corners, intersections, borders, etc.).

    If you do not provide a style, the default is AsciiTable.BASIC_ASCII.

    // Example of passing a custom border style
    Character[] borderStyle = AsciiTable.FANCY_ASCII;
    System.out.println(AsciiTable.getTable(borderStyle, data, columns));
  7. Use AsciiTable.builder() for advanced customization

    master

    For more control over the table output, use AsciiTable.builder(). This allows you to customize the line separator, change the border style, and write the output directly to an OutputStream instead of printing to standard output.

    try (OutputStream fos = Files.newOutputStream(Paths.get("table.txt"))) {
        AsciiTable.builder()
                .lineSeparator("\r\n")
                .border(AsciiTable.BASIC_ASCII_NO_OUTSIDE_BORDER)
                .data(planets, Arrays.asList(
                        new Column().with(planet -> Integer.toString(planet.num)),
                        new Column().header("Name").footer("Average").headerAlign(CENTER).dataAlign(RIGHT).with(planet -> planet.name),
                        new Column().header("Diameter").headerAlign(RIGHT).dataAlign(CENTER).footerAlign(CENTER)
                                .footer(String.format("%.03f", planets.stream().mapToDouble(planet -> planet.diameter).average().orElse(0)))
                                .with(planet -> String.format("%.03f", planet.diameter)),
                        new Column().header("Mass").headerAlign(RIGHT).dataAlign(LEFT)
                                .footer(String.format("%.02f", planets.stream().mapToDouble(planet -> planet.mass).average().orElse(0)))
                                .with(planet -> String.format("%.02f", planet.mass)),
                        new Column().header("Atmosphere").headerAlign(LEFT).dataAlign(CENTER).with(planet -> planet.atmosphere)))
                .writeTo(fos);
    }
  8. Add a footer to an AsciiTable

    master

    A footer is a special row at the end of the table. It can be used to repeat headers for long tables or to display summary information like totals or averages. You define a footer for a specific column using the .footer(String) method on a Column object. You can also control the alignment of the footer text using .footerAlign(Alignment).

    System.out.println(AsciiTable.getTable(planets, Arrays.asList(
            new Column().with(planet -> Integer.toString(planet.num)),
            new Column().header("Name").footer("Average").headerAlign(CENTER).dataAlign(RIGHT).with(planet -> planet.name),
            new Column().header("Diameter").headerAlign(RIGHT).dataAlign(CENTER).footerAlign(CENTER)
                    .footer(String.format("%.03f", planets.stream().mapToDouble(planet -> planet.diameter).average().orElse(0)))
                    .with(planet -> String.format("%.03f", planet.diameter)),
            new Column().header("Mass").headerAlign(RIGHT).dataAlign(LEFT)
                    .footer(String.format("%.02f", planets.stream().mapToDouble(planet -> planet.mass).average().orElse(0)))
                    .with(planet -> String.format("%.02f", planet.mass)),
            new Column().header("Atmosphere").headerAlign(LEFT).dataAlign(CENTER).with(planet -> planet.atmosphere))));
  9. Create a table using the Stream API

    master

    Use AsciiTableCollector.toAsciiTable(...) to collect elements from a Stream directly into an ASCII table. This approach is memory-efficient as it does not require materializing the stream into an intermediate list. You can pass columns as individual arguments or as a List<ColumnData<T>>. You can also specify a border style as the first argument.

    try (Stream<String> lines = Files.lines(Paths.get("planets.csv"))) {
        String table = lines
                .skip(1) // skip header
                .map(line -> parsePlanet(line))
                .collect(AsciiTableCollector.toAsciiTable(
                        new Column().with(planet -> Integer.toString(planet.num)),
                        new Column().header("Name").with(planet -> planet.name),
                        new Column().header("Diameter").dataAlign(HorizontalAlign.RIGHT).with(planet -> String.format("%.03f", planet.diameter))));
    
        System.out.println(table);
    }
  10. Set minimum and maximum column widths

    master

    Control column sizing using Column.minWidth(int) and Column.maxWidth(int). Setting a maxWidth will trigger overflow behavior when the content exceeds the limit.

    System.out.println(AsciiTable.getTable(planets, Arrays.asList(
            new Column().minWidth(5).with(planet -> Integer.toString(planet.num)),
            new Column().header("Name").with(planet -> planet.name),
            new Column().header("Diameter").with(planet -> String.format("%.03f", planet.diameter)),
            new Column().header("Mass").with(planet -> String.format("%.02f", planet.mass)),
            new Column().header("Atmosphere Composition").maxWidth(12).with(planet -> planet.atmosphere))));
  11. Align column headers and data

    master

    Use Column.headerAlign(HorizontalAlign) and Column.dataAlign(HorizontalAlign) to set the horizontal alignment for headers and data independently. Supported alignments are provided by the HorizontalAlign enum (e.g., LEFT, RIGHT, CENTER).

    System.out.println(AsciiTable.getTable(planets, Arrays.asList(
            new Column().with(planet -> Integer.toString(planet.num)),
            new Column().header("Name").headerAlign(HorizontalAlign.CENTER).dataAlign(HorizontalAlign.LEFT).with(planet -> planet.name),
            new Column().header("Diameter").with(planet -> String.format("%.03f", planet.diameter)),
            new Column().header("Mass").with(planet -> String.format("%.02f", planet.mass)),
            new Column().header("Atmosphere").headerAlign(HorizontalAlign.RIGHT).dataAlign(HorizontalAlign.CENTER).with(planet -> planet.atmosphere))));
  12. Configure overflow behavior for columns

    master

    When a cell reaches its maxWidth, you can control how the text is handled using OverflowBehaviour.

    Available behaviors:

    • OverflowBehaviour.NEWLINE: Inserts a newline (default).
    • OverflowBehaviour.CLIP_LEFT: Clips text from the left.
    • OverflowBehaviour.CLIP_RIGHT: Clips text from the right.
    • OverflowBehaviour.ELLIPSIS_LEFT: Adds ellipsis to the left.
    • OverflowBehaviour.ELLIPSIS_RIGHT: Adds ellipsis to the right.
    • OverflowBehaviour.ELLIPSIS_CENTER: Adds ellipsis in the center.
    // Example of different overflow behaviors
    System.out.println(AsciiTable.getTable(planets, Arrays.asList(
            new Column().header("Atmosphere Composition").maxWidth(12, OverflowBehaviour.NEWLINE).with(planet -> planet.atmosphere),
            new Column().header("Atmosphere Composition").maxWidth(12, OverflowBehaviour.CLIP_LEFT).with(planet -> planet.atmosphere),
            new Column().header("Atmosphere Composition").maxWidth(12, OverflowBehaviour.CLIP_RIGHT).with(planet -> planet.atmosphere),
            new Column().header("Atmosphere Composition").maxWidth(12, OverflowBehaviour.ELLIPSIS_LEFT).with(planet -> planet.atmosphere),
            new Column().header("Atmosphere Composition").maxWidth(12, OverflowBehaviour.ELLIPSIS_RIGHT).with(planet -> planet.atmosphere),
            new Column().header("Atmosphere Composition").maxWidth(12, OverflowBehaviour.ELLIPSIS_CENTER).with(planet -> planet.atmosphere))));