Токенизация строки CSV, экранирование двойных кавычек - PullRequest
2 голосов
/ 25 октября 2019

У меня есть строка CSV, разделенная запятой:

1000102257,b,N,159999,3,4545656,4,,,,"6,125% NORDRHEIN-WESTF.LA.SCHA.R.239 21.12. "18"

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

Как видитепоследний токен является изолятом между двойными кавычками, но появляется еще одна двойная кавычка ("18), которая разрушает механизм токенизации:

"6,125% NORDRHEIN-WESTF.LA.SCHA.R.239 21.12. "18"

Это мой код для разбиения токенов на строку:

public static void main(String[] args) {
    final String cvsSplitterEscapingQuotes = ",(?=([^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*$)";
    String strLine = "1000102257,b,N,159999,3,4545656,4,,,,\"6,125% NORDRHEIN-WESTF.LA.SCHA.R.239 21.12. \"18\"";
    String[] tokens = strLine.split(cvsSplitterEscapingQuotes, -1);
}

Как я могу избежать средних двойных кавычек, которые находятся в кавычках?

Ответы [ 3 ]

4 голосов
/ 25 октября 2019

Не разбирайте CSV самостоятельно, используйте библиотеку. Даже у такого простого формата, как CSV, есть нюансы: поля могут быть экранированы кавычками или не экранированы, файл может иметь или не иметь заголовок и так далее. Кроме того, вы должны протестировать и поддерживать код, который вы написали. Так что писать меньше кода и повторно использовать библиотеки - это хорошо.

В Java есть множество библиотек для CSV:

ИМХО, первые два являются самыми популярными.

Вот пример для Apache Commons CSV:

final Reader in = new FileReader("counties.csv");
final Iterable<CSVRecord> records = CSVFormat.DEFAULT.parse(in);

for (final CSVRecord record : records) { // Simply iterate over the records via foreach loop. All the parsing is handler for you
    String populationString = record.get(7); // Indexes are zero-based
    String populationString = record.get("population"); // Or, if your file has headers, you can just use them

    … // Do whatever you want with the population
}

Посмотрите, как это просто! И это будет похоже на другие парсеры.

0 голосов
/ 25 октября 2019

Это неэкранированное регулярное выражение, проверенное здесь :

(".*"|[^,"]+|(?<=,)(?=,))

разделяет вашу строку запятыми, но без строки в кавычках. Вот как это работает:

(                          // Start the match
 ".*"                      // Greedily match anything in quotes
     |[^,"]+               // Or, greedily match anything that isn't a comma or quote
            |(?<=,)(?=,)   // Or, look behind for a comma and ahead for a comma
                           //    (the empty match)
                        )  // End match.

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

|^(?=,)           // At the beginning, look forward for a comma
       |(?<=,)$   // Look back for a comma, and at the end

Итак, весь шаблон таков:

(".*"|[^,"]+|(?<=,)(?=,))|^(?=,)|(?<=,)$

Но, как говорит @madhead, если это не домашнее задание, используйте библиотеку!

0 голосов
/ 25 октября 2019

Просто игнорируйте двойные кавычки, которые не следуют за запятой или переносом строки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...