Nice looking table with StringBuilder

前端 未结 2 1112
慢半拍i
慢半拍i 2020-12-22 09:35

I know that \"printf\" method can use string formatting.

My question is : Is there a way to create a nice looking table with StringBuilder class?

For exampl

相关标签:
2条回答
  • 2020-12-22 09:37

    A simple approach is, of course, to create hard-wired printf statements. However, this is not very flexible, because you always have to fix the column widths, and the functions will always be specific for one class and its fields.

    So I'd like to propose a helper class that mainly does two things:

    • Encapsulates the creation of table cell entries (via a Java 8 Function)
    • Computes the maximum width of each columnm for a given set of elements.

    Let there be a given model class, like a Person, for example:

    class Person
    {
        int getId() { ... }
        String getFirstName() { ... }
        String getLastName() { ... }
        float getHeight()  { ... }
    }
    

    Then, I'd like to create a "nice" table as follows:

    TableStringBuilder<Person> t = new TableStringBuilder<Person>();
    t.addColumn("id", Person::getId);
    t.addColumn("first name", Person::getFirstName);
    t.addColumn("last name", Person::getLastName);
    t.addColumn("height", Person::getHeight);
    String s = t.createString(persons);
    

    And I'd expect the contents of this string to be a nicely formatted table:

       id|   first name|    last name|height
    -----+-------------+-------------+------
    41360|Xvnjhpdqdxvcr|    Stvybcwvm|   1.7
     3503|      Krxvzxk|      Xtspsjd|   1.6
    41198|       Uegqfl|  Qlocfljbepo|  1.58
    26517|       Somyar|       Aopufo|  1.77
    13773| Dxehxjbhwgsm|     Jgnlonjv|  1.77
    13067|       Zozitk|       Jbozwd|  1.81
    46534|        Bosyq|      Kcprrdc|  1.55
    93862|    Rlfxblgqp|   Pgrntaqoos|  1.85
    12155|   Kjpjlavsqc|Rxfrrollhwhoh|  1.79
    75712|        Fwpnd|     Mwcsshwx|  1.78
    

    Here is a MVCE that shows such a TableStringBuilder and its application:

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    import java.util.function.Function;
    
    public class TableStringTest
    {
        public static void main(String[] args)
        {
            List<Person> persons = new ArrayList<Person>();
            for (int i=0; i<10; i++)
            {
                persons.add(new Person());
            }
    
            TableStringBuilder<Person> t = new TableStringBuilder<Person>();
            t.addColumn("id", Person::getId);
            t.addColumn("first name", Person::getFirstName);
            t.addColumn("last name", Person::getLastName);
            t.addColumn("height", Person::getHeight);
    
            String s = t.createString(persons);
            System.out.println(s);
        }
    }
    
    
    class TableStringBuilder<T>
    {
        private final List<String> columnNames;
        private final List<Function<? super T, String>> stringFunctions;
    
        TableStringBuilder()
        {
            columnNames = new ArrayList<String>();
            stringFunctions = new ArrayList<Function<? super T, String>>();
        }
    
        void addColumn(String columnName, Function<? super T, ?> fieldFunction)
        {
            columnNames.add(columnName);
            stringFunctions.add((p) -> (String.valueOf(fieldFunction.apply(p))));
        }
    
        private int computeMaxWidth(int column, Iterable<? extends T> elements)
        {
            int n = columnNames.get(column).length();
            Function<? super T, String> f = stringFunctions.get(column);
            for (T element : elements)
            {
                String s = f.apply(element);
                n = Math.max(n, s.length());
            }
            return n;
        }
    
        private static String padLeft(String s, char c, int length)
        {
            while (s.length() < length)
            {
                s = c + s;
            }
            return s;
        }
    
        private List<Integer> computeColumnWidths(Iterable<? extends T> elements)
        {
            List<Integer> columnWidths = new ArrayList<Integer>();
            for (int c=0; c<columnNames.size(); c++)
            {
                int maxWidth = computeMaxWidth(c, elements);
                columnWidths.add(maxWidth);
            }
            return columnWidths;
        }
    
        public String createString(Iterable<? extends T> elements)
        {
            List<Integer> columnWidths = computeColumnWidths(elements);
    
            StringBuilder sb = new StringBuilder();
            for (int c=0; c<columnNames.size(); c++)
            {
                if (c > 0)
                {
                    sb.append("|");
                }
                String format = "%"+columnWidths.get(c)+"s";
                sb.append(String.format(format, columnNames.get(c)));
            }
            sb.append("\n");
            for (int c=0; c<columnNames.size(); c++)
            {
                if (c > 0)
                {
                    sb.append("+");
                }
                sb.append(padLeft("", '-', columnWidths.get(c)));
            }
            sb.append("\n");
    
            for (T element : elements)
            {
                for (int c=0; c<columnNames.size(); c++)
                {
                    if (c > 0)
                    {
                        sb.append("|");
                    }
                    String format = "%"+columnWidths.get(c)+"s";
                    Function<? super T, String> f = stringFunctions.get(c);
                    String s = f.apply(element);
                    sb.append(String.format(format, s));
                }
                sb.append("\n");
            }
            return sb.toString();
        }
    }
    
    
    //Dummy Person Class
    class Person
    {
        private int id;
        private String firstName;
        private String lastName;
        private float height;
    
        private static Random random = new Random(0);
    
        Person()
        {
            id = random.nextInt(100000);
            firstName = createRandomString();
            lastName = createRandomString();
            height = (150 + random.nextInt(40)) / 100.0f;
        }
    
        private static String createRandomString()
        {
            int length = random.nextInt(10) + 5;
            StringBuilder sb = new StringBuilder();
            char offset = 'A';
            for (int i=0; i<length; i++)
            {
                char c = (char)(random.nextInt(26) + offset);
                sb.append(c);
                offset = 'a';
            }
            return sb.toString();
        }
    
        int getId()
        {
            return id;
        }
    
        String getFirstName()
        {
            return firstName;
        }
    
        String getLastName()
        {
            return lastName;
        }
    
        float getHeight()
        {
            return height;
        }
    }
    
    0 讨论(0)
  • 2020-12-22 09:51

    Ok, so thank you for all the answer who was nice to me.

    I figured out that we could do it by that way :

    public String toString(){
        StringBuilder s = new StringBuilder();
    
        s.append(String.format("%-20s%-20s%-20s%-20s%-20s%-20s%-20s\n","Identifier","Category","Level","Space","Type","Dimension","Limits"));
        s.append(String.format("=============================================================================================================================================\n"));
        for(String id : this.idTable.keySet()) {
            s.append(String.format("%-20s",id));
            s.append(this.idTable.get(id).toString());
            //s.append("Identifier: " +id+" "+this.idTable.get(id).toString()+"\n");
        }
        return s.toString();
    }
    

    Notice, the String.format which do all the work i wanted and didn't know before !

    Regardind to you @Marco13, You did a very good job !!!! Thanks all !

    P.S.: I will aprove the message from @Marco13 , because his implementation is very good also !

    0 讨论(0)
提交回复
热议问题