忽略错误,将Unicode流重新编码为Ascii



我试图获取一个包含奇数字符的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() 一次加载到内存中

您混淆了编码和解码端。

对于解码,你做得很好。您将其作为二进制数据打开,chardet是第一个1K,然后使用检测到的编码以文本模式重新打开。

但是,您试图通过使用codecs.getreader将已经解码的数据进一步解码为ASCII。该函数返回一个StreamReader对流中的数据进行解码。这行不通。您需要数据编码为ASCII。

但目前还不清楚为什么首先要使用codecs流解码器编码器,而你只想一次性编码一段文本,这样你就可以记录它。为什么不直接调用encode方法呢?

log(csv_file.read().encode('ascii', 'ignore'))

如果你想要一些可以用作行的惰性迭代的东西,可以构建一些完全通用的东西,但只做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")

或者,更简单地说:

with io.open(self.csv_path, 'r', encoding=detectedEncoding) as csv_file:
    csv_ascii_stream = (line.encode('ascii', 'ignore') for line in csv_file)

我有点迟到了,但这里有一个替代解决方案,使用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()等,我想您可能需要使用此功能。如果您只需要对流进行迭代,那么提供的生成器表达式abarnert会更简洁一些。

相关内容

  • 没有找到相关文章

最新更新