Как я могу использовать System.getProperty ("line.separator"). ToString ()? - PullRequest
21 голосов
/ 19 августа 2010

У меня есть строка с разделителями табуляции (представляющая таблицу), которая передается моему методу.Когда я печатаю его в командной строке, он выглядит как таблица со строками:

http://i.stack.imgur.com/2fAyq.gif

Окно команд правильно буферизовано.Я думаю, что перед каждой строкой или после нее определенно есть новый символ строки.

Моя проблема заключается в том, что я хочу разделить входящую строку на отдельные строки, представляющие строки таблицы.Пока что у меня есть:

private static final String newLine = System.getProperty("line.separator").toString();
private static final String tab = "\t";
private static String[] rows;
...

rows = tabDelimitedTable.split(newLine);    //problem is here

System.out.println();
System.out.println("################### start debug ####################");

System.out.println((tabDelimitedTable.contains(newLine)) ? "True" : "False");

System.out.println("#################### end debug###################");
System.out.println();

output:

################### start debug ####################
False
#################### end debug###################

Очевидно, что в строке есть что-то, указывающее ОС начать новую строку.Тем не менее он, по-видимому, не содержит символов новой строки.

Запуск последней версии JDK в Windows XP SP3.

Любые идеи?

Ответы [ 7 ]

30 голосов
/ 19 августа 2010

проблема

Вы должны НЕ предполагать, что произвольный входной текстовый файл использует "правильный" специфичный для платформы разделитель newline . Это кажется источником вашей проблемы; это не имеет ничего общего с регулярным выражением.

Для иллюстрации на платформе Windows System.getProperty("line.separator") равно "\r\n" (CR + LF). Однако, когда вы запускаете свой Java-код на этой платформе, вам, вполне возможно, придется иметь дело с входным файлом, разделителем строк которого является просто "\n" (LF). Возможно, этот файл изначально был создан на платформе Unix, а затем передан в бинарном (а не текстовом) режиме в Windows. Может быть много сценариев, в которых вы можете столкнуться с такими ситуациями, когда вы должны проанализировать текстовый файл как ввод, который не использует разделитель новой строки текущей платформы.

(Кстати, когда текстовый файл Windows переносится в Unix в двоичном режиме, многие редакторы отображают ^M, что смущает некоторых людей, которые не понимают, что происходит).

Когда вы производите текстовый файл в качестве вывода, вам, вероятно, следует предпочесть платформенный разделитель новой строки, но когда вы используете текстовый файл в качестве ввода, это, вероятно, Можно с уверенностью предположить, что он правильно использует разделитель новой строки для конкретной платформы.


Решение

Один из способов решения проблемы - использовать, например, java.util.Scanner. Он имеет метод nextLine(), который может возвращать следующую строку (если она существует), корректно обрабатывая любые несоответствия между разделителем новой строки платформы и входным текстовым файлом.

Вы также можете комбинировать 2 Scanner, один для сканирования файла строка за строкой, а другой для сканирования токенов каждой строки. Вот простой пример использования, который разбивает каждую строку на List<String>. Таким образом, весь файл становится List<List<String>>.

Это, вероятно, лучший подход, чем чтение всего файла в один огромный String, а затем split в строки (которые затем split в части).

    String text
        = "row1\tblah\tblah\tblah\n"
        + "row2\t1\t2\t3\t4\r\n"
        + "row3\tA\tB\tC\r"
        + "row4";

    System.out.println(text);
    //  row1    blah    blah    blah
    //  row2    1   2   3   4
    //  row3    A   B   C
    //  row4

    List<List<String>> input = new ArrayList<List<String>>();

    Scanner sc = new Scanner(text);
    while (sc.hasNextLine()) {
        Scanner lineSc = new Scanner(sc.nextLine()).useDelimiter("\t");
        List<String> line = new ArrayList<String>();
        while (lineSc.hasNext()) {
            line.add(lineSc.next());
        }
        input.add(line);
    }
    System.out.println(input);
    // [[row1, blah, blah, blah], [row2, 1, 2, 3, 4], [row3, A, B, C], [row4]]

Смотри также

  • Effective Java 2nd Edition, Item 25: Предпочитать списки массивам

Смежные вопросы

28 голосов
/ 19 августа 2010

Попробуйте

rows = tabDelimitedTable.split("[" + newLine + "]");

Это должно решить проблему regex .

Также не так важно, но тип возврата

System.getProperty("line.separator")

- это String , поэтому нет необходимости вызывать toString ().

2 голосов
/ 19 августа 2010

Попробуйте BufferedReader.readLine() вместо всего этого усложнения. Он распознает все возможные ограничители строки.

2 голосов
/ 19 августа 2010

В Windows line.separator является комбинацией CR / LF (ссылка здесь ).

Метод Java String.split() принимает регулярное выражение . Поэтому я думаю, что здесь есть некоторая путаница.

1 голос
/ 19 августа 2010

Попробуйте это:

rows = tabDelimitedTable.split("[\\r\\n]+");

Это должно работать независимо от того, какие разделители строк находятся на входе, и игнорирует пустые строки.

1 голос
/ 19 августа 2010

Остальные респонденты правы, что split () принимает в качестве аргумента регулярное выражение, поэтому вам придется сначала это исправить.Другая проблема заключается в том, что вы предполагаете, что символы разрыва строки совпадают с системными значениями по умолчанию.В зависимости от того, откуда поступают данные и где выполняется программа, это предположение может быть неверным.

1 голос
/ 19 августа 2010

Я думаю, что ваша проблема в том, что String.split() обрабатывает свой аргумент как регулярное выражение, а регулярные выражения обрабатывают специальные строки.Вам может понадобиться явно создать объект регулярного выражения для передачи в split() (существует другая его перегрузка) и настроить это регулярное выражение для разрешения новых строк, передавая MULTILINE в параметре flags Pattern.compile(). Docs

...