从列表中删除对象的字节顺序标记

3
我正在使用Python(3.4,在Windows 7上)下载一组文本文件,但当我读取(并在修改后写入)这些文件时,其中保留的值中出现了一些字节顺序标记(BOM),主要是UTF-8 BOM。最终,我将每个文本文件用作列表(或字符串),但似乎无法删除这些BOM。所以我想知道是否有可能删除BOM?
更多背景信息:这些文本文件是从公共ftp源下载的,用户上传自己的文档,因此原始编码高度可变且未知于我。为确保下载不出错,我将编码指定为UTF-8(使用latin-1会导致错误)。所以我拥有BOM并不神秘,我不认为预先编码/解码的解决方案对我有帮助( Convert UTF-8 with BOM to UTF-8 with no BOM in Python) - 实际上它似乎会增加其它BOM的频率。
当我下载后修改这些文件时,我使用以下语法:
with open(t, "w", encoding='utf-8') as outfile:
    with open(f, "r", encoding='utf-8') as infile:
        text = infile.read
        #Arguments to make modifications follow

稍后,在将“outfiles”读取为列表后,我发现一些单词带有UTF-8 BOM,例如 \ufeff 。我尝试使用以下列表理解式删除BOM:

g = list_outfile    #Outfiles now stored as list
g = [i.replace(r'\ufeff','') for i in g]

尽管此参数将运行,但不幸的是BOM仍然存在,例如,当我打印列表时(我相信即使我尝试从字符串而不是列表中删除BOM,也会遇到类似的问题:如何删除此特殊字符?)。如果我在列表推导式中放入一个普通单词(非BOM),那个单词将被替换。
我确实理解,如果我逐个打印列表对象,BOM将不会出现(Python中的特殊国家字符不会.split())。并且BOM不在原始文本文件中。但我担心,在运行后续文本分析参数时,这些BOM将保留下来,因此任何以\ufeffword而不是word出现在列表中的对象都将被分析为\ufeffword。
再次提醒,是否可能事后删除BOM?

因此,原始编码非常多变并且对我来说是未知的。- 那么,您应该以二进制模式而不是文本模式打开。您不知道编码,所以不要撒谎说您知道。 - Kevin
@Kevin:说得好。我确实尝试了二进制模式,但后来在写文件时遇到了问题。我认为我可以使用outfile.write(bytes(text, "UTF-8"))解决这个问题,尽管我不太确定是否会再次引入编码(解码?)问题(还有其他要探索的格式问题)。 - bauerandrew
如果以二进制模式打开两个文件,则将读取字节对象(在2.x中为str,在2.7中别名为bytes,在3.x中完全重命名)并写入字节对象。不需要进行任何转换。 - Kevin
1个回答

0
问题在于您正在替换特定字节,而您的字节顺序标记的表示可能会因文件的编码方式而异。 使用codecs库检查BOM的存在非常简单。Codecs具有不同UTF编码的特定字节顺序标记。此外,您可以从打开的文件中自动获取编码方式,无需指定它。 假设您正在使用utf-8编码读取csv文件,该文件可能使用字节顺序标记,也可能不使用。然后,您可以像这样进行操作:
import codecs

with open("testfile.csv", "r") as csvfile:
    line = csvfile.readline()
    if line.__contains__(codecs.BOM_UTF8.decode(csvfile.encoding)):
        # A Byte Order Mark is present
        line = line.strip(codecs.BOM_UTF8.decode(csvfile.encoding))
    print(line)

在上面的代码输出中,您将看到没有字节顺序标记的输出。为了进一步改进,您还可以将此检查限制为仅在文件的第一行上执行(因为字节顺序标记始终驻留在文件的前几个字节中,即文件的开头)。 使用strip而不是replace不会替换任何内容,如果指定的字节顺序标记不存在,则实际上不会执行任何操作。因此,您甚至可以跳过对字节顺序标记的手动检查,并仅对文件的整个内容运行strip方法:
import codecs

with open("testfile.csv", "r") as csvfile:
    with open("outfile.csv", "w") as outfile:
        outfile.write(csvfile.read().strip(codecs.BOM_UTF8.decode(csvfile.encoding)))

完成后,您将得到一个名为“outfile.csv”的文件,其中包含与原始文件(testfile.csv)完全相同的内容,但不包括字节顺序标记。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接