代码之家  ›  专栏  ›  技术社区  ›  Damiii

使用StringBuilder的漂亮表格

  •  0
  • Damiii  · 技术社区  · 9 年前

    我知道“printf”方法可以使用字符串格式。

    我的问题是: 有没有方法用StringBuilder类创建一个漂亮的表?

    例如:

    |Id|Category|Level|Space|Type|Adress|Dimension|Limits|

    在该行下,我必须添加每列的值!

    这样做: example 但使用StringBuilder


    所以社区希望看到我的答案(我不明白为什么……但无论如何我都会这么说!)

    public String toString(){
        StringBuilder s = new StringBuilder();
    
        s.append("Category: "+this.category+"\t");
        s.append("Level: "+this.level.toString()+"\t");
    
        return s.toString();
    }
    

    现在解释一下,为什么看到我的答案会帮助我?我真的很想看看你的答案!

    2 回复  |  直到 9 年前
        1
  •  11
  •   Community Dai    7 年前

    当然,一个简单的方法是创建硬连线 printf 声明。但是,这不是很灵活,因为您总是必须固定列宽,并且函数总是特定于一个类及其字段。

    所以我想提出一个助手类,它主要做两件事:

    • 封装表单元格条目的创建(通过Java8 Function )
    • 计算给定元素集的每个列的最大宽度。

    让有一个给定的模型类,比如 Person 例如:

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

    然后,我想创建一个“漂亮”的表,如下所示:

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

    我希望这个字符串的内容是一个格式良好的表:

       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
    

    这里是 a MVCE 显示了这样一个 TableStringBuilder 及其应用:

    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;
        }
    }
    
        2
  •  3
  •   Damiii    9 年前

    好的,谢谢你对我好的回答。

    我想我们可以这样做:

    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();
    }
    

    注意 String.format 它完成了我以前不知道的所有工作!

    谢谢你@Marco13,你做得很好!!!! 谢谢大家!

    备注:我会转发@Marco13的消息,因为他的实现也很好!