¿Cómo excluir U+2028 de los separadores de línea en Python al leer el archivo?
Pregunta
Tengo un archivo en UTF-8, donde algunas líneas contienen el carácter de separador de línea U+2028 (http://www.fileformat.info/info/unicode/char/2028/index.htm). No quiero que sea tratado como un descanso de línea cuando leo líneas del archivo. ¿Hay alguna forma de excluirlo de los separadores cuando itero sobre el archivo o uso readlines ()? (Además de leer todo el archivo en una cadena y luego dividirse por n.) ¡Gracias!
Solución
No puedo duplicar este comportamiento en Python 2.5, 2.6 o 3.0 en Mac OS X - U+2028 siempre se trata como no endline. ¿Podría entrar en más detalles sobre dónde ves este error?
Dicho esto, aquí hay una subclase de la clase de "archivo" que podría hacer lo que quieras:
#/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")
Otros consejos
No pude reproducir ese comportamiento, pero aquí hay una solución ingenua que solo fusiona los resultados de lectura hasta que no terminan con 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
Gracias a todos por responder. Creo que sé por qué no hayas podido replicar esto. Me di cuenta de que sucede si decodeo el archivo al abrir, como en:
f = codecs.open(filename, encoding='utf-8')
for line in f:
print line
Las líneas no están separadas en U2028, si abro el archivo primero y luego decodifique las líneas individuales:
f = open(filename)
for line in f:
print line.decode("utf8")
(Estoy usando Python 2.6 en Windows. El archivo fue originalmente UTF16LE y luego se convirtió en UTF8).
Esto es muy interesante, supongo que no usaré códecs. Abra mucho de ahora en adelante :-).
Si usa Python 3.0 (tenga en cuenta que no lo hago, así que no puedo probar), de acuerdo con el documentación puedes pasar un opcional newline
parámetro open
para especificar qué seperator de línea usar. Sin embargo, la documentación no menciona U+2028 en absoluto (solo se menciona \r
, \n
, y \r\n
Como separadores de línea), por lo que en realidad es una sorpresa para mí que esto ocurre (aunque puedo confirmar esto incluso con Python 2.6).
El módulo de códecs está haciendo lo correcto. U+2028 se denomina "separador de línea" con el comentario "puede usarse para representar esta semántica inequívocamente". Por lo tanto, tratarlo como un separador de línea es sensato.
Presumiblemente, el Creador no habría puesto los caracteres U+2028 allí sin una buena razón ... ¿El archivo también tiene " n"? ¿Por qué quieres que las líneas no se dividan en U+2028?