I have a Tab-delimited String (representing a table) that is passed to my method. When I print it to the command line, it appears like a table with rows:
http://i.stack.imgur.com/2fAyq.gif
The command window is correctly buffered. My thinking is that there is definitely a new line character before or after each row.
My problem is that I want to split up the incoming string into individual strings representing the rows of the table. So far I have:
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###################
Obviously there is something in the string telling the OS to start a new line. Yet it apparently contains no newline characters.
Running the latest JDK on Windows XP SP3.
Any Ideas?
Попробуйте
rows = tabDelimitedTable.split("[" + newLine + "]");
. Это должно решить проблему регулярного выражения .
Также не так важно, но тип возвращаемого значения
System.getProperty("line.separator")
- String , поэтому вызывать toString () не нужно.
В Windows line.separator представляет собой комбинацию CR / LF (ссылка здесь ).
Метод Java String.split ()
принимает регулярное выражение . Так что я думаю, здесь есть некоторая путаница.
Попробуйте BufferedReader.readLine()
вместо всех этих сложностей. Он распознает все возможные терминаторы строк.
Вы должны НЕ считать, что произвольный входной текстовый файл использует "правильный" специфический для платформы newline разделитель. Похоже, это и есть источник вашей проблемы; это имеет мало общего с regex.
Для примера, на платформе Windows System.getProperty("line.separator")
- "\r\n"
(CR+LF). Однако, когда вы запускаете свой Java-код на этой платформе, вы вполне можете иметь дело с входным файлом, разделитель строк которого просто "\n"
(LF). Возможно, этот файл был изначально создан на платформе Unix, а затем передан в двоичном (а не текстовом) режиме в Windows. Может быть много сценариев, в которых вы можете столкнуться с подобными ситуациями, когда вы должны разобрать текстовый файл в качестве входного, который не использует разделитель новой строки текущей платформы.
(По совпадению, когда текстовый файл Windows передается в Unix в двоичном режиме, многие редакторы отображают ^M
, что сбивает с толку некоторых людей, которые не понимают, что происходит).
Когда вы производите текстовый файл в качестве выходного, вы, вероятно, должны предпочесть специфический для платформы разделитель новой строки, но когда вы потребляете текстовый файл в качестве входного, вероятно, небезопасно делать предположение, что он правильно использует специфический для платформы разделитель новой строки.
Одним из способов решения проблемы является использование, например, java.util.Scanner
. В нем есть метод nextLine()
который может вернуть следующую строку (если она существует), правильно обрабатывая любое несоответствие между разделителем новой строки платформы и входным текстовым файлом.
Вы также можете объединить 2 Scanner
, один для сканирования файла построчно, а другой для сканирования токенов каждой строки. Вот простой пример использования, который разбивает каждую строку на List
. Таким образом, весь файл становится List
. >
Это, вероятно, лучший подход, чем чтение всего файла в одну огромную String
, а затем разбиение
на строки (которые затем разбиваются
на части).
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.util.Scanner
- имеет много примеров использованияПопробуйте следующее:
rows = tabDelimitedTable.split("[\\r\\n]+");
Это должно работать независимо от того, какие разделители строк используются во вводе, и будет игнорировать пустые строки.
Я думаю, ваша проблема в том, что String.split ()
обрабатывает свой аргумент как регулярное выражение, а регулярные выражения обрабатывают символы новой строки специально. Возможно, вам потребуется явно создать объект регулярного выражения для передачи в split ()
(есть еще одна его перегрузка) и настроить это регулярное выражение, чтобы разрешить новые строки, передав MULTILINE
в параметре флагов Pattern.compile ()
. Docs
Другие респонденты правы, что разделение () принимает в качестве аргумента регулярное выражение, поэтому сначала вам нужно исправить это. Другая проблема заключается в том, что вы предполагаете, что символы разрыва строки такие же, как и в системе по умолчанию. В зависимости от того, откуда поступают данные и где работает программа, это предположение может быть неверным.