преобразовать разделенную запятыми (с пробелом) строку в столбцы под соответствующими значениями из самой строки - PullRequest
0 голосов
/ 29 декабря 2011

У меня есть вывод в консоли из моего кода, как в примере, приведенном ниже,

... columns=20xs, viewport_supported=true, wta=false, ..., mmf=false
... columns=11xs, viewport_supported=false, wta=false, ..., mmf=true 
... columns=15xs, viewport_supported=true, wta=false, ..., mmf=false

Я хочу перестроить его, извлекая общую строку слева от знака '=' и помещая ее в качестве заголовка столбца и его значений в столбец. Как начать делать это на Java?

Я ищу вывод, как показано ниже:

columns      viewport_supported        wta     and so on
  20xs              true              false
  11xs              false             false
  15xs              true              false

Ответы [ 4 ]

1 голос
/ 29 декабря 2011

Хорошо, здесь идет.Вот решение, использующее Guava

Сначала вот вспомогательный класс с именем Table (не путать с интерфейсом Table в Guava):

public class Table {

    private static final MapSplitter MAP_SPLITTER = 
        Splitter.on(',').trimResults().withKeyValueSeparator(Splitter.on('='));

    private final Multimap<String, String> values = 
            Multimaps.newListMultimap(
                // keys are sorted, values maintain insertion order
                Maps.<String, Collection<String>>newTreeMap(),
                new Supplier<List<String>>() {
                    @Override public List<String> get() {
                        return Lists.newArrayList();
                    }
                });

    // keys are sorted, to correspond with the order of the other map
    private final Map<String, Integer> lengths = Maps.newTreeMap();

    private int modCount = 0;

    public void addRow(final String row) {
        modCount++;
        final Map<String, String> lineData = MAP_SPLITTER.split(row);
        final boolean empty = values.isEmpty();
        if (!empty && values.keySet().size() != lineData.size()) {
            throw new IllegalArgumentException("Bad row: " + row);
        }

        for (final Entry<String, String> entry : lineData.entrySet()) {
            final String key = entry.getKey();
            final String value = entry.getValue();
            if (!empty && !values.containsKey(key)) {
                throw new IllegalArgumentException(
                    "Bad column: " + key + " in row " + row);
            }

            final Integer tempLength;
            if (empty) {
                tempLength = key.length();
            } else {
                tempLength = lengths.get(key);
            }

            values.put(key, value);
            lengths.put(key, Math.max(value.length(), tempLength));
        }
    }

    public Iterable<String> getHeaders() {
        return Collections.unmodifiableSet(values.asMap().keySet());
    }

    public Iterable<Integer> getColumnSizes() {
        return Collections.unmodifiableCollection(lengths.values());
    }

    public Iterable<Iterable<String>> getData() {
        return new Iterable<Iterable<String>>() {

            @Override
            public Iterator<Iterable<String>> iterator() {
                return new RowIterator();
            }
        };
    }
    private class RowIterator extends AbstractIterator<Iterable<String>> {
        private int rowIndex = -1;
        private final int modCount = Table.this.modCount;
        private final int maxRow = 
                     values.asMap().values().iterator().next().size() - 1;

        @Override
        protected Iterable<String> computeNext() {
            if (Table.this.modCount != modCount) {
                throw new ConcurrentModificationException();
            }

            final Map<String, Collection<String>> map = values.asMap();
            if (rowIndex++ == maxRow) {
                return endOfData();
            }

            final List<String> data =
                Lists.newArrayListWithCapacity(map.size());
            for (final Collection<String> column : map.values()) {
                data.add(((List<String>) column).get(rowIndex));
            }

            return Collections.unmodifiableCollection(data);
        }

    }

}

Теперь мыможно использовать этот класс таблицы для форматирования ваших данных:

final String input = "columns=20xs, viewport_supported=true, wta=false, mmf=false\n"
        + "columns=11xs, viewport_supported=false, wta=false, mmf=true \n"
        + "columns=15xs, viewport_supported=true, wta=false, mmf=false";
final Table table = new Table();
final Iterable<String> lines = Splitter.on('\n').trimResults().split(input);
for (final String line : lines) {
    // add one row of data
    table.addRow(line);
}

// Using Appendable so you can easily switch to some other implementation,
// e.g. System.out
final Appendable appendable = new StringBuilder();

final Iterable<Integer> columnSizes = table.getColumnSizes();
final Iterable<String> headers = table.getHeaders();
final Iterator<String> headerIterator = headers.iterator();
final Iterable<Iterable<String>> data = table.getData();
{

    // write headers
    boolean first = true;
    for (final Integer size : columnSizes) {
        if (first) {
            first = false;
        } else {
            appendable.append(" | ");
        }

        appendable.append(Strings.padEnd(headerIterator.next(), size, ' '));
    }

    appendable.append('\n');
}

{

    // underline headers
    boolean first = true;
    for (final Integer size : columnSizes) {
        if (first) {
            first = false;
        } else {
            appendable.append("-+-");
        }

        appendable.append(Strings.repeat("-", size));
    }

    appendable.append('\n');
}

// write data
for (final Iterable<String> row : data) {
    boolean first = true;
    final Iterator<String> rowIterator = row.iterator();
    for (final Integer size : columnSizes) {
        if (first) {
            first = false;
        } else {
            appendable.append(" | ");
        }

        appendable.append(Strings.padEnd(rowIterator.next(), size, ' '));
    }

    appendable.append('\n');
}

System.out.println(appendable);

А вот вывод:

columns | mmf   | viewport_supported | wta  
--------+-------+--------------------+------
20xs    | false | true               | false
11xs    | true  | false              | false
15xs    | false | true               | false

Это будет намного сложнее, если ваши строки имеют переменное содержимое (не все строкисодержат одинаковые столбцы), поэтому я обязал все строки содержать одинаковые столбцы.Не стесняйтесь изменить это (или что-нибудь еще).

1 голос
/ 29 декабря 2011

Взгляните на метод split класса String. Возможно, вы захотите использовать его для разделения каждой строки на отдельные секции column=value, а затем снова для отделения столбца от значения. Это должно начать вас - спросите еще раз, если вы застряли.

0 голосов
/ 03 января 2012

Я наконец смог сделать это следующим образом: разделить строку с помощью метода split (), создать динамический массив Map и назначить ключ и значение для строки соответственно по обе стороны от «equals to sign». Затем распечатывает информацию заголовка, анализируя карту, представляющую первую строку данных, и затем печатает все строки данных, повторяя объекты из карты. выдержки из моего кода приведены ниже.

/* delimiter */
            String delimiter = ", ";

// данная строка будет разделена указанным разделителем аргумента.

            String[] temp = capabilities.split(delimiter);

            /* print substrings */
            Map<String, String> row = new HashMap<String, String>();
            for (int i = 0; i < temp.length; i++) {
                String delimiter1 = "=";
                String[] temp1 = null;
                temp1 = temp[i].split(delimiter1);
                if (temp1 != null && temp1.length == 2) {
                    row.put(temp1[0], temp1[1]);
                }
            }
            dataRows.add(row);
// print the header --- but first, get the header information by parsing the map representing the first data row
        List<String> fieldNames = new ArrayList<String>();
        Map<String, String> firstRow = dataRows.get(0);
        for (String fieldName : firstRow.keySet()) { 
            fieldNames.add(fieldName);
        }
        for (String fieldName : fieldNames) {
                            System.out.print("\t" + fieldName);

        }

        // now, print all data rows
        for (Map<String, String> dataRow : dataRows) { 
            System.out.println("\n");
            for (String fieldName : fieldNames) {
            System.out.print("\t" + dataRow.get(fieldName));}

Спасибо всем за помощь.

0 голосов
/ 29 декабря 2011

Я недавно сделал то же самое, что вы пытаетесь сделать.

Я не уверен, как хранятся ваши данные, но для демонстрации я использую строку «a». Допустим, строка «a» содержит:

String a = 20xs, true, false;

затем вы можете использовать функцию split(), чтобы разбить предложение String и разделить его на слово String. Следующий код делает это:

a = a.trim();
String[] words = a.split(","); // creates array of Strings with each words in String a
// words would contain [20xs] [true] [false] 

Я написал функцию, которая будет вставлять пробелы в конце каждого слова.

/** Add spaces to Strings so that all of the are of same number of characters
 *  @param str  String to be padded
 *  @param n    total number words String should be padded to
 * @return str  Padded string 
 */
private String padString(String str, int n){
    if(str.length() < n){
        for(int j = str.length(); j < n; j++){
            str += " ";
        } // end for
    } // end if

    return str;
} // end padString

так что теперь давайте скажем, если вы делаете:

System.out.println(padString(words[0],15) + padString(words[1],15) + padString(words[2],15)                   

// So the result will be [20xs           ] [true           ] [false          ] 

Вы получите следующее в консоли, когда напишите код выше:

20xs           true           false    

Вы можете передать большее значение в функции padString(), если вам нужны большие пробелы.
Как я вижу, заголовок столбца все время один и тот же, вы можете сначала написать код println с одинаковым количеством отступов, поэтому он всегда начинается с начала и действует как заголовок.

Надеюсь, это поможет.

...