Как исключить U + 2028 из разделителей строк в Python при чтении файла?

У меня есть файл в UTF-8, где некоторые строки содержат символ разделителя строк U+2028 (http://www.fileformat.info/info/unicode/char/2028/index.htm). Я не хочу, чтобы это рассматривалось как разрыв строки, когда я читаю строки из файла. Есть ли способ исключить его из разделителей, когда я перебираю файл или использую readlines()? (Помимо чтения всего файла в строку и последующего разделения на \n.) Спасибо!


person user135773    schedule 09.07.2009    source источник
comment
Почему бы не перейти на U+2028 и не избавиться от динозавров CR/LF?   -  person Milind R    schedule 11.12.2014


Ответы (5)


Я не могу повторить это поведение в python 2.5, 2.6 или 3.0 на mac os x — U + 2028 всегда рассматривается как неконечная строка. Не могли бы вы подробнее рассказать о том, где вы видите эту ошибку?

Тем не менее, вот подкласс класса «файл», который может делать то, что вы хотите:

#/usr/bin/python
# -*- coding: utf-8 -*-
class MyFile (file):
    def __init__(self, *arg, **kwarg):
        file.__init__(self, *arg, **kwarg)
        self.EOF = False
    def next(self, catchEOF = False):
        if self.EOF:
            raise StopIteration("End of file")
        try:
            nextLine= file.next(self)
        except StopIteration:
            self.EOF = True
            if not catchEOF:
                raise
            return ""
        if nextLine.decode("utf8")[-1] == u'\u2028':
            return nextLine+self.next(catchEOF = True)
        else:
            return nextLine

A = MyFile("someUnicode.txt")
for line in A:
    print line.strip("\n").decode("utf8")
person Markus    schedule 09.07.2009
comment
кто-то с лучшим знанием юникода в Python, правильная ли эта строка: if nextLine.decode("utf8")[-1] == u'\u2028': Я получал предупреждение без оператора декодирования, не совсем понимаю, почему. - person Markus; 10.07.2009
comment
Я не знаю, какое сообщение об ошибке вы получаете, но обычно, если строка содержит символы, отличные от ascii, то ее необходимо сначала декодировать в «строку юникода», прежде чем она будет обработана любой другой операцией. Так что обычно это 1. декодировать, 2. делать что-то со строкой, 3. кодировать обратно перед записью в файл при обработке файлов utf. - person user135773; 10.07.2009

Я не мог воспроизвести такое поведение, но вот наивное решение, которое просто объединяет результаты строки чтения до тех пор, пока они не заканчиваются на U+2028.

#!/usr/bin/env python

from __future__ import with_statement

def my_readlines(f):
  buf = u""
  for line in f.readlines():
    uline = line.decode('utf8')
    buf += uline
    if uline[-1] != u'\u2028':
      yield buf
      buf = u""
  if buf:
    yield buf

with open("in.txt", "rb") as fin:
  for l in my_readlines(fin):
    print l
person Alexander Ljungberg    schedule 09.07.2009

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

f = codecs.open(filename, encoding='utf-8')
for line in f:
    print line

На u2028 строки не разделены, если сначала открыть файл, а потом декодировать отдельные строки:

f = open(filename)
for line in f:
    print line.decode("utf8")

(Я использую Python 2.6 в Windows. Первоначально файл был UTF16LE, а затем он был преобразован в UTF8).

Это очень интересно, думаю, теперь я не буду часто использовать codecs.open :-).

person user135773    schedule 09.07.2009

Если вы используете Python 3.0 (обратите внимание, что я этого не делаю, поэтому я не могу тестировать), в соответствии с документация, вы можете передать необязательный параметр newline в open, чтобы указать, какой разделитель строк использовать. Однако в документации вообще не упоминается U + 2028 (в качестве разделителей строк упоминаются только \r, \n и \r\n), поэтому для меня на самом деле удивительно, что это вообще происходит (хотя я могу подтвердить это даже с Python 2.6) .

person balpha    schedule 09.07.2009

Модуль кодеков делает ПРАВИЛЬНУЮ вещь. U + 2028 назван «РАЗДЕЛИТЕЛЬ СТРОКИ» с комментарием «может использоваться для однозначного представления этой семантики». Поэтому разумно рассматривать его как разделитель строк.

Предположительно, создатель не стал бы помещать туда символы U + 2028 без уважительной причины ... в файле также есть u"\n"? Почему вы хотите, чтобы строки в U+2028 не разделялись?

person John Machin    schedule 10.07.2009
comment
Рассматривать его как разделитель строк разумно, однако вопрос тоже разумен. Бывают случаи, когда файлы данных могут содержать недезинфицированные строки, содержащие этот символ, и вы хотите обработать их, не нарушая этот символ. - person Nick; 29.08.2012