我正在尝试使用包含奇数字符的Unicode文件流,并将其包装为将其转换为Ascii的流式读取器,忽略或替换所有无法编码的字符。
我的信息流看起来像:
"EventId","Rate","Attribute1","Attribute2","(。・ω・。)ノ"
...
我试图动态改变流看起来像这样:
import chardet, io, codecs
with open(self.csv_path, 'rb') as rawdata:
detected = chardet.detect(rawdata.read(1000))
detectedEncoding = detected['encoding']
with io.open(self.csv_path, 'r', encoding=detectedEncoding) as csv_file:
csv_ascii_stream = codecs.getreader('ascii')(csv_file, errors='ignore')
log( csv_ascii_stream.read() )
log
行的结果是:UnicodeEncodeError: 'ascii' codec can't encode characters in position 36-40: ordinal not in range(128)
,即使我使用errors='ignore'
显式构建了StreamReader
我希望得到的流(读取时)如下:
"EventId","Rate","Attribute1","Attribute2","(?????)?"
...
或者"EventId","Rate","Attribute1","Attribute2","()"
(使用'ignore'
代替'replace'
)
为什么异常会发生呢?
我已经看到很多用于解码字符串的问题/解决方案,但我的挑战是在读取流时(使用.next()
)更改流,因为该文件可能太大而无法加载到内存中立即使用.read()
答案 0 :(得分:1)
您正在混合编码和解码端。
对于解码,你做得很好。您将其作为二进制数据打开,chardet
第一个1K,然后使用检测到的编码以文本模式重新打开。
但是,您正在尝试使用codecs.getreader
进一步将已解码的数据解码为ASCII。该函数返回StreamReader
,从流中解码数据。那不会起作用。您需要将数据编码为ASCII。
但不清楚为什么你首先使用codecs
流解码器或编码器,当你想做的只是编码一个大块文本一次性,所以你可以记录它。为什么不调用encode
方法?
log(csv_file.read().encode('ascii', 'ignore'))
如果你想要一些你可以用作懒的可迭代行的东西,你可以构建一些完全通用的东西,但是只做像{{1}这样的事情要简单得多csv
文档中的示例:
UTF8Recorder
或者,更简单:
class AsciiRecoder:
def __init__(self, f, encoding):
self.reader = codecs.getreader(encoding)(f)
def __iter__(self):
return self
def next(self):
return self.reader.next().encode("ascii", "ignore")
答案 1 :(得分:1)
我对这个派对来说有点晚了,但这是另一种解决方案,使用codecs.StreamRecoder
:
from codecs import getencoder, getdecoder, getreader, getwriter, StreamRecoder
with io.open(self.csv_path, 'rb') as f:
csv_ascii_stream = StreamRecoder(f,
getencoder('ascii'),
getdecoder(detectedEncoding),
getreader(detectedEncoding),
getwriter('ascii'),
errors='ignore')
print(csv_ascii_stream.read())
如果您需要能够灵活地在流上调用read()
/ readlines()
/ seek()
/ tell()
等,我猜您可能想要使用此功能得到回报。如果你只需要迭代流,那么提供的生成器表达式就会更加简洁。