Почему CSVWriter и CSVReader используют разные escape-символы по умолчанию?
Вот мой фрагмент кода, который я использую:
StringWriter writer = new StringWriter();
CSVWriter csvwriter = new CSVWriter(writer);
String[] originalValues = new String[2];
originalValues[0] = "t\\est";
originalValues[1] = "t\\est";
System.out.println("Original values: " + originalValues[0] +"," + originalValues[1]);
csvwriter.writeNext(originalValues);
csvwriter.close();
CSVReader csvReader = new CSVReader(new StringReader(writer.toString()));
String[] resultingValues = csvReader.readNext();
System.out.println("Resulting values: " + resultingValues[0] +"," + resultingValues[1]);
Вывод приведенного фрагмента:
Original values: t\est,t\est
Resulting values: test,test
Символ обратной косой черты ('\') исчезает после преобразования!!!
Путем некоторого базового анализа я понял, что это происходит потому, что CSVReader
использует обратную косую черту ('\') в качестве escape-символа по умолчанию, где как CSVWriter
использует двойную кавычку ('"') в качестве escape-символа по умолчанию.
В чем причина этого несоответствия в поведении по умолчанию?
Чтобы решить вышеуказанную проблему, мне удалось найти следующие два решения:
1) Перезаписать управляющий символ по умолчанию в CSVReader нулевым символом:
CSVParser csvParser = new CSVParserBuilder().withEscapeChar('\0').build();
CSVReader csvReader = new CSVReaderBuilder(new StringReader(writer.toString())).withCSVParser(csvParser).build();
2) Использование RFC4180Parser, который строго следует стандартам RFC4180:
RFC4180Parser rfc4180Parser = new RFC4180ParserBuilder().build();
CSVReader csvReader = new CSVReaderBuilder(new StringReader(writer.toString())).withCSVParser(rfc4180Parser).build();
Может ли использование любого из вышеперечисленных подходов вызывать побочные эффекты у любых других персонажей?
И почему RFC4180Parser
не парсер по умолчанию? Это только для поддержания обратной совместимости, как RFC4180Parser
познакомился в более поздних версиях?
1 ответ
Я думаю, что мы смотрим на 2 вида побега здесь.
1) Избегание двойной кавычки в CSV:
test,"Monitor 24"", Samsung"
test,"Monitor 24\", Samsung" // Linux style
Поскольку у нас во втором поле запятая, это поле должно быть заключено в двойные кавычки. Любые двойные кавычки внутри этого поля должны быть экранированы, ""
или же \"
,
2) \
также является общим экранирующим символом, например \t
(вкладка) или \n
(новая линия).
И с тех пор 'e'
нет в списке символов, чтобы убежать, \
просто игнорируется и удаляется.
Так что, если бы вы написали "t\\\\est"
файл будет содержать "t\\est"
(избежал обратной косой черты) и показать "t\est"
после прочтения. Или писать "\\test"
вероятно, покажет tab
а также "est"
после прочтения.
Чтобы сохранить \
после прочтения вам действительно придется как-то сказать парсеру игнорировать эти последовательности, но текущее поведение не выглядит мне противоречивым - на самом деле они оба рассматривают \
как побег персонажа.