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

Привет у меня есть текстовый файл со строкой:

привет,"фу, бар"

я хочу разделить его на список как:

['hello', '"foo, bar"']

Есть ли способ, которым я могу достичь этого?

Я пытаюсь это на данный момент:

for line in sys.stdin: csv_file = StringIO.StringIO(line) csv_reader = csv.reader(csv_file)

Я хочу, чтобы они разбились на две строки, т.е.

'hello' and '"foo, bar"'

4 ответа

Допустим, вы прочитали строку из CSV:

from StringIO import StringIO
import csv

infile = StringIO('hello,"foo, bar"')
reader = csv.reader(infile)
row = reader.next()  # row is ['hello', 'foo, bar']

Второе значение в строке foo, bar вместо "foo, bar", Это не какая-то странность Python, это разумная интерпретация синтаксиса CSV. Кавычки, вероятно, были размещены не для того, чтобы быть частью значения, а для того, чтобы показать, что foo, bar это одно значение и не должно быть разбито на foo а также bar на основе запятой (,). Альтернативным решением было бы избежать запятой при создании файла CSV, поэтому строка будет выглядеть так:

hello,foo \,bar

Поэтому довольно странная просьба - сохранить эти цитаты. Если мы знаем больше о вашем случае использования и более широкой картине, мы можем помочь вам лучше. Чего ты пытаешься достичь? Откуда берется входной файл? Это действительно CSV или какой-то другой синтаксис, который выглядит похожим? Например, если вы знаете, что каждая строка состоит из двух значений, разделенных запятой, и первое значение никогда не содержит запятой, то вы можете просто разделить первую запятую:

print 'hello,"foo, bar"'.split(',', 1)  # => ['hello', '"foo, bar"']

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

Если вы пытаетесь снова написать в CSV, кавычки будут воссозданы, как вы это делаете. Они не должны быть там в промежуточном списке:

outfile = StringIO()
writer = csv.writer(outfile)
writer.writerow(row)
print outfile.getvalue()

Это напечатает

hello,"foo, bar"

Вы можете настроить точный выход CSV, установив новый диалект.

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

# We're going to write individual strings, so we don't want a line terminator
csv.register_dialect('no_line_terminator', lineterminator='')

def maybe_quote_string(s):
    out = StringIO()

    # writerow iterates over its argument, so don't give it a plain string
    # or it'll break it up into characters
    csv.writer(out, 'no_line_terminator').writerow([s])

    return out.getvalue()

print maybe_quote_string('foo, bar')
print map(maybe_quote_string, row)

Выход:

"foo, bar"
['hello', '"foo, bar"']

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

Я скажу это снова, вы, вероятно, идете по неверному пути с этим вопросом. Другие, вероятно, согласятся. Вот почему вы изо всех сил пытаетесь получить хорошие ответы. Какую большую проблему вы пытаетесь решить? Мы можем помочь вам лучше достичь этого.

Kinda зависит от вашего варианта использования. Если для значений, содержащих запятые (например, «foo,bar»), есть только «s», вы можете использовать CSV-запись, чтобы вернуть их обратно.

      import io
import csv

infile = io.StringIO('hello,"foo, bar"')
outfile = io.StringIO()
reader = csv.reader(infile)
for row in reader:
    inList = row
    break
print(inList)
# As an output string
writer = csv.writer(outfile)
writer.writerow(inList)
outList = outfile.getvalue().strip()
print(outList)
# As a List
outList = []
for i in range(len(inList)):
    outfile = io.StringIO()
    writer = csv.writer(outfile)
    writer.writerow([inList[i]])
    outList.append(outfile.getvalue().strip())
print(outList)

Выход

      ['hello', 'foo, bar']
hello,"foo, bar"
['hello', '"foo, bar"']

Однако, если у вас есть другие ненужные "s", которые вы хотите сохранить (например, "hello", "foo, bar", humbug'), и все поля, содержащие , будут правильно заключены в "s", тогда вы можете разделить строку на и найдите «битые» поля (начинайте с «но не заканчивайте»)

      line = '"hello","foo, bar",humbug'
fields = line.split(',')
print(fields)
values = []
i = 0
while i < len(fields):
    # If a field doesn't start with a ", or starts and ends with "s
    if (fields[i][0] != '"') or (fields[i][-1] == '"'):
        values.append(fields[i])        # It's a stand alone value
        i += 1
        continue
    value = fields[i]           # A value that has been split
    i += 1
    while i < len(fields):
        value += ',' + fields[i]
        i += 1
        if value[-1] == '"':     # The last part would have ended in a "
            break
    values.append(value)
print(values)

Выход

      ['"hello"', '"foo', ' bar"', 'humbug']
['"hello"', '"foo, bar"', 'humbug']

Немного опоздал на вечеринку, но в библиотеке CSV есть цитата, которая должна делать то, что вы хотите (установите значение QUOTE_NONE)

Хорошо, так что это заняло много времени, чтобы найти решение, и это ни в коем случае не красиво, но:

>>> import re
>>> s = 'hello,"foo, bar"'
>>> 
>>> replacements = {}
>>> m = re.search("\".*\"", s)
>>> while m:
...     key = 'unique_phrase_' + str(len(replacements))
...     replacements[key] = s[m.span()[0]:m.span()[1]]
...     s = re.sub("\".*\"", key, s, count=1)
...     m = re.search("\".*\"", s)
... 
>>> list_from_string = s.split(",")
>>> final_list = []
>>> for element in list_from_string:
...     for key in replacements.keys():
...             if re.match(key, element):
...                     final_list.append(re.sub(key, replacements[key],   element))
...             else:
...                     final_list.append(element)
... 
>>> 
>>> print final_list
['hello', '"foo, bar"']

Выглядит мне некрасиво, но не смог найти четких способов сделать его более питоническим.

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