Читатель CSV Python: нужно игнорировать запятую в кавычках в качестве разделителя

Мне нужно проанализировать текстовый файл по запятой, а не по запятой в кавычках.
Это выглядит как тривиальная задача, но заставить Python сделать ее правильно невозможно. В основном из-за того, что перед строкой в ​​кавычках стоит строка без кавычек, из-за чего CSV, вероятно, не очень хорошо отформатирован, но мне это нужно именно так.

Пример ввода:

cmd,print "AA"
cmd, print "AA,BB,CC"
cmd,   print " AA, BB, CC ", separate-window

Желаемый результат (в синтаксисе Python):

[['cmd', 'print "AA"'], 
 ['cmd', 'print "AA,BB,CC"'], 
 ['cmd', 'print " AA, BB, CC "', 'separate-window']]

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

csv.reader также разделяется запятыми в кавычках, так что я предпочитаю получать ['cmd', 'print "AA', 'BB', 'CC"'].

shlex с измененными .whitespace=',' и .whitespace_split=True почти помогает, но удаляет кавычки ['cmd', 'print AA, BB, CC']. Мне нужно сохранить кавычки.

Думал о re.split, но у меня очень слабое представление о том, как работает (?=) штука...

Нашел здесь несколько похожих тем, но ни один из предложенных ответов мне не помог.

ОБНОВЛЕНИЕ: скриншот для тех, кто сомневается, делаю ли я именно то, что описываю:

csv.reader тоже разделяется запятыми в кавычках. Это не должно быть. Пожалуйста, покажите нам точный код, который вы использовали, и точный входной файл.

John Gordon 04.04.2024 21:48

Точный входной файл, который я предоставил. Точный код: с open(test_list_name) как csvfile: rtl_data = csv.reader(csvfile, delimiter=',', quotechar='"', Skipinitialspace=True) для дополненной_строки в rtl_data: row = tuple(cell.strip() для ячейка в Padded_row)

Noob 04.04.2024 21:55

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

Barmar 04.04.2024 21:58

@Jean-BaptisteYunès Как это поможет? Во входном файле нет символов '.

Barmar 04.04.2024 21:59

Это недопустимый файл CSV.

Barmar 04.04.2024 21:59

Если вы не можете исправить входной файл, вам нужно будет написать собственный синтаксический анализатор, который проверяет наличие двойных кавычек. Я не думаю, что вы можете сделать это с помощью регулярного выражения, они плохо различают «внутренние кавычки» от «внешних кавычек».

Barmar 04.04.2024 22:00

@Barmar да, я сказал в вопросе: «Возможно, это не очень хорошо отформатированный CSV, но мне он нужен именно такой». Это заставляет меня сомневаться в том, что вы проверяли мой реальный пример ввода.

Noob 04.04.2024 22:02

Что ты имеешь в виду? Я удалил свой комментарий о том, что получил желаемый результат, потому что посмотрел еще раз и увидел, что это неправильно.

Barmar 04.04.2024 22:03

@barmar прочитал слишком быстро...

Jean-Baptiste Yunès 04.04.2024 22:12

@JohnGordon вот скриншот i.sstatic.net/nMMxT.png, ясно, что программа чтения csv НЕ делает то, что мне нужно. Хотелось бы увидеть скриншот, подтверждающий ваши слова.

Noob 04.04.2024 22:15

Я неправильно понял вывод, когда запускал ваш код, и удалил свой предыдущий комментарий. Бармар прав, это неверный файл CSV. Вы не можете заключать в кавычки только часть столбца, весь столбец должен быть в кавычках.

John Gordon 04.04.2024 22:39

@JohnGordon задолго до того, как «Бармар был прав», я написал точно то же самое в своем вопросе - это неправильно сформированный CSV. К счастью, его комментарий о «внутренних кавычках» дал мне подсказку, что гуглить, и я нашел решение.

Noob 04.04.2024 22:57
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
12
51
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

def parse_line(line: str) -> list[str]:
  in_quote = False
  start = 0
  output = []
  stripped_line = line.strip()
  for index, char in enumerate(stripped_line):
    if char == '"':
      in_quote = not in_quote
    if char == ',' and not in_quote:
      output.append(stripped_line[start:index])
      start = index + 1
  else:
    if index + 1 != start:
      output.append(stripped_line[start:len(stripped_line)])
  return output

for line in csvfile:
  print(parse_line(line))

['cmd', 'print "AA"']
['cmd', ' print "AA,BB,CC"']
['cmd', '   print " AA, BB, CC "', ' separate-window']

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

Noob 04.04.2024 22:46
Ответ принят как подходящий

Погуглив еще немного и удалив слово «python» из запроса, я нашел решение. По какой-то теме, связанной с Java, был задан очень похожий вопрос. И ответ был: использовать regex.
Итак, я настроился на Python и вот точный код, который мне подходит:

import re
splitter = re.compile(r',(?=(?:[^"]*"[^"]*")*[^"]*$)')
with open('example.txt') as csvfile:
  for padded_row in csvfile:
    stripped_row = padded_row.rstrip()
    row = splitter.split(stripped_row)
    print(row)

Подробное объяснение, как это работает
Спасибо комментаторам, вы действительно дали мне несколько подсказок, как улучшить мои запросы в Google :)

Другие вопросы по теме