Неожиданное поведение универсального режима новой строки с модулями StringIO и csv - PullRequest
4 голосов
/ 06 февраля 2012

Рассмотрим следующее (Python 3.2 под Windows):

>>> import io
>>> import csv
>>> output = io.StringIO()         # default parameter newline=None
>>> csvdata = [1, 'a', 'Whoa!\nNewlines!']
>>> writer = csv.writer(output, quoting=csv.QUOTE_NONNUMERIC)
>>> writer.writerow(csvdata)
25
>>> output.getvalue()
'1,"a","Whoa!\nNewlines!"\r\n'

Почему существует один \n - если бы он не был преобразован в \r\n, так как универсальныйвключен режим перевода строки?

Если этот параметр включен, на входе окончания строк \n, \r или \r\n переводятся в \n довернулся к звонящему.И наоборот, при вывод , \n переводится в системный разделитель строк по умолчанию, os.linesep.

Ответы [ 2 ]

6 голосов
/ 06 февраля 2012

«Одиночный» \n встречается как символ данных внутри третьего поля. Следовательно, это поле заключено в кавычки, так что читатель CSV будет рассматривать его как часть данных. Это НЕ «терминатор строки» (должен называться разделителем строк) или его часть. Чтобы лучше оценить цитату, удалите quoting=csv.QUOTE_NONNUMERIC.

\r\n создается потому, что csv оканчивает строки с dialect.lineterminator, по умолчанию \r\n. Другими словами, настройка «универсальные новые строки» игнорируется.

Обновление

Документы 2.7 и 3.2 для io.StringIO практически идентичны в отношении новой строки arg.

Аргумент newline работает аналогично аргументу TextIOWrapper. По умолчанию не переводить перевод строки.

Мы рассмотрим первое предложение ниже. Второе предложение верно для вывода, в зависимости от вашей интерпретации «по умолчанию» и «перевода новой строки».

TextIOWrapper docs:

символ новой строки может быть None, '', '\ n', '\ r' или '\ r \ n'. Это контролирует обработка концов строк. Если нет, универсальные переводы включен. При включенном на входе окончании строк '\ n', '\ r' или «\ r \ n» переводятся в «\ n», прежде чем возвращаются вызывающей стороне. И наоборот, при выводе '\ n' переводится в системную строку по умолчанию разделитель, ос.линесеп. Если новая строка является любой из его законных значений, эта строка становится новой строкой, когда файл читается и вернулся непереведенный. На выходе '\ n' преобразуется в новую строку.

Python 3.2 в Windows:

>>> from io import StringIO as S
>>> import os
>>> print(repr(os.linesep))
'\r\n'
>>> ss = [S()] + [S(newline=nl) for nl in (None, '', '\n', '\r', '\r\n')]
>>> for x, s in enumerate(ss):
...     m = s.write('foo\nbar\rzot\r\n')
...     v = s.getvalue()
...     print(x, m, len(v), repr(v))
...
0 13 13 'foo\nbar\rzot\r\n'
1 13 12 'foo\nbar\nzot\n'
2 13 13 'foo\nbar\rzot\r\n'
3 13 13 'foo\nbar\rzot\r\n'
4 13 13 'foo\rbar\rzot\r\r'
5 13 15 'foo\r\nbar\rzot\r\r\n'
>>>

Строка 0 показывает, что «default», которое вы получаете без аргумента newline, не подразумевает перевода \n (или любого другого символа). Это, безусловно, НЕ конвертирует '\n' в os.linesep

Строка 1 показывает, что то, что вы получаете с newline=None (должно совпадать со строкой 0, не так ли ??), действительно INPUT универсальный перевод новой строки - причудливо!

Строка 2: newline='' не изменяется, как и строка 0. Она, безусловно, НЕ преобразует '\n' в ''.

Строки 3, 4 и 5: как говорят документы, '\n' преобразуется в значение newline arg.

Эквивалентный код Python 2.X дает эквивалентные результаты с Python 2.7.2.

Обновление 2 Для согласованности со встроенным open() по умолчанию должно быть os.linesep, как задокументировано. Чтобы получить поведение без перевода при выводе, используйте newline=''. Примечание: документы open() намного понятнее. Завтра я отправлю отчет об ошибке.

2 голосов
/ 06 февраля 2012

С документы для StringIO:

Аргумент newline работает аналогично аргументу TextIOWrapper. По умолчанию перевод новой строки не производится.

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

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

...