Как использовать System.getProperty( "line.separator" ). ToString()?
У меня есть строка с разделителями табуляции (представляющая таблицу), которая передается моему методу. Когда я печатаю его в командной строке, он выглядит как таблица со строками:
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();
выход:
################### start debug ####################
False
#################### end debug###################
Очевидно, что в строке есть что-то, указывающее ОС начать новую строку. Тем не менее, он, очевидно, не содержит символов новой строки.
Запуск последней версии JDK в Windows XP SP3.
Есть идеи?
Ответы
Ответ 1
Try
rows = tabDelimitedTable.split("[" + newLine + "]");
Это должно решить проблему регулярное выражение.
Также не этот важный, но возвращаемый тип
System.getProperty("line.separator")
Строка, поэтому нет необходимости вызывать toString().
Ответ 2
Проблема
Вы НЕ должны предполагать, что в произвольном текстовом файле ввода используется "правильный" раздел 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]]
См. также
- Эффективное Java 2nd Edition, пункт 25: Предпочтительные списки для массивов
Связанные вопросы
Ответ 3
В Windows, line.separator представляет собой комбинацию CR/LF (ссылка здесь).
Метод Java String.split()
принимает регулярное выражение. Поэтому я думаю, что здесь есть путаница.
Ответ 4
Попробуйте BufferedReader.readLine()
вместо всех этих осложнений. Он распознает все возможные терминаторы линий.
Ответ 5
Я думаю, ваша проблема в том, что String.split()
рассматривает свой аргумент как регулярное выражение, а регулярные выражения обрабатывают новые строки специально. Возможно, вам нужно будет явно создать объект регулярного выражения для перехода к split()
(есть другая перегрузка) и настроить это регулярное выражение, чтобы разрешить символы новой строки, передав MULTILINE
в параме тлях Pattern.compile()
. Docs
Ответ 6
Другие респонденты верны, что split() принимает в качестве аргумента регулярное выражение, поэтому сначала вам нужно исправить это. Другая проблема заключается в том, что вы предполагаете, что символы разрыва строки такие же, как и по умолчанию. В зависимости от того, откуда поступают данные и где работает программа, это предположение может быть неверным.
Ответ 7
Попробуйте следующее:
rows = tabDelimitedTable.split("[\\r\\n]+");
Это должно работать независимо от того, какие разделители строк находятся на входе, и будет игнорировать пустые строки.
Ответ 8
Вы также можете использовать writer.writeLine()
Это напишет текст и добавит новую строку (используя конец строки платформы)