Как использовать System.getProperty (line.separator) .toString ()?

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

https://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.

Любые идеи?


person ejsuncy    schedule 18.08.2010    source источник
comment
Почему .toString ()? Он уже String, если он не равен нулю, и в этом случае вы получите исключение NullPointerException.   -  person user207421    schedule 19.08.2010
comment
Да, я просто хотел убедиться, что передаю строку вместо символа в .split (). Я должен был прочитать документацию по методу .getProperty (), но написание .toString () было быстрее, чем открытие моего браузера lol.   -  person ejsuncy    schedule 19.08.2010


Ответы (7)


Пытаться

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

Это должно решить проблему регулярного выражения.

Также не так важно, но возвращаемый тип

System.getProperty("line.separator")

является String, поэтому вызывать toString () не нужно.

person Kerem Baydoğan    schedule 18.08.2010
comment
Спасибо, это сработало. Думаю, я просто прочитал документацию по методу split () и увидел, что он взял String, не понимая разницы между регулярным выражением и String. - person ejsuncy; 19.08.2010
comment
Если это Windows, а символ новой строки "\r\n", это фактически split между \r и \n, создавая ложные пустые строки. - person polygenelubricants; 19.08.2010

Проблема

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

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

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

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


Решение

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

Вы также можете комбинировать 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: Предпочитайте списки массивам

Связанные вопросы

person polygenelubricants    schedule 19.08.2010
comment
Спасибо, что нашли время ответить. Я попробовал одно из других решений, и оно сработало (это было быстрее, чем устанавливать сканеры в нужных местах). Поскольку это лишь небольшая часть моей java-программы, и поскольку я точно знаю, каким будет ввод (это не произвольный текстовый файл ввода), я могу использовать символ новой строки по умолчанию. Я рассмотрел другой метод, который вернул эту входную строку, и он использует символ платформы по умолчанию. Тем не менее, спасибо за вашу помощь. - person ejsuncy; 19.08.2010
comment
Я разбирал заголовки электронной почты Outlook pst в Linux, и комментарий ^ M помог мне понять вывод cat -A. Определенно не хотел свойство line.separator в моем случае. - person ; 04.01.2016

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

person user207421    schedule 19.08.2010

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

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

person Brian Agnew    schedule 18.08.2010

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

person rmeador    schedule 18.08.2010
comment
Флаг MULTILINE применяется только тогда, когда вы используете флаги начала / конца (^ и $) в своем регулярном выражении. - person James Van Huis; 19.08.2010
comment
Флаг MULTILINE также вызывает расширение. символ, чтобы распознать разделители строк как совпадающие. - person James Van Huis; 19.08.2010
comment
@James: нет, согласно спецификациям (и согласно моим тестам) MULTILINE (? M) не вызывает расширение. символ для соответствия разделителям строк. Это будет флаг (?) DOTALL - person Maarten Bodewes; 15.06.2011

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

person Mike Baranczak    schedule 18.08.2010
comment
Вау ... Responders звучит так круто. Я собираюсь использовать это с этого момента. - person NullUserException; 19.08.2010

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

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

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

person James Van Huis    schedule 18.08.2010
comment
Изначально я хотел, чтобы эта java-программа работала и на Mac / Linux. отсюда и метод System.getProperty (). - person ejsuncy; 19.08.2010
comment
У вас все еще может быть ввод, который включает разделители строк, не являющиеся системными по умолчанию. Это регулярное выражение будет перехватывать все комбинации независимо от платформы и ввода. - person James Van Huis; 19.08.2010