Почему String.split нужно экранировать разделитель каналов?

140

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

private ArrayList<String> parseLine(String line) {
    ArrayList<String> list = new ArrayList<String>();
    String[] list_str = line.split("\\|"); // note the escape "\\" here
    System.out.println(list_str.length);
    System.out.println(line);
    for(String s:list_str) {
        list.add(s);
        System.out.print(s+ "|");
    }
    return list;
}

Может кто-нибудь объяснить, почему для split()метода нужно экранировать символ трубы ?

начать его
источник
13
Ответы ниже ответили на вопрос «почему», но, к вашему сведению, если вы пытаетесь сопоставить буквальную строку, вы также можете посмотреть Pattern.quote . Он принимает Stringи возвращает регулярное выражение, Stringкоторое будет соответствовать вводу (т. Е. Позаботится обо всех экранированиях за вас).
yshavit
+1 дляPattern.quote
redDevil

Ответы:

175

String.splitожидает аргумент регулярного выражения. Неэкранированное |выражение анализируется как регулярное выражение, означающее «пустая строка или пустая строка», что вы не имеете в виду.

Луи Вассерман
источник
76

Поскольку синтаксис этого параметра для разделения - это регулярное выражение, где в '|' имеет особое значение OR, а '\ |' означает буквальное "|" поэтому строка "\\ |" означает регулярное выражение '\ |' что означает точное совпадение с символом '|'.

dlamblin
источник
1
Спасибо за это объяснение. Я почти всегда забываю использовать двойной выход. Теперь, когда я знаю, почему это так, это наверняка поможет мне вспомнить с этого момента.
sufinawaz
Что произойдет, если в значении строки String есть символы канала? Как бы вы могли разделить, не разделив ускользнувшую трубу \ | ?
AlexandreJ
@AlexandreJ Вы спрашиваете, как разбить строку, которая выглядит так: Some|Delimited|Text|With|An\|Embedded|Pipe|Charна ("Some", "Delimited", "Text", "With", "An\|Embedded", "Pipe", "Char")? Функция разделения не поддерживает такое экранирование, но вы могли бы создать регулярное выражение, которое будет работать в этом случае, например, с отрицательным утверждением нулевой ширины, выглядящим позади группы: (?<!\\)\|это будетline.split("(?<!\\\\)\\|");
dlamblin
6

Вы можете просто сделать это:

String[] arrayString = yourString.split("\\|");
Равинат
источник
вам нужно избежать \, чтобы использовать ваше регулярное выражение "yourString.split (" \\ | ")", это правильная формула.
mautrok 07