首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在Python中将带BOM的UTF-8转换为不带BOM的UTF-8

在Python中将带BOM的UTF-8转换为不带BOM的UTF-8
EN

Stack Overflow用户
提问于 2012-01-18 00:37:53
回答 6查看 137.9K关注 0票数 92

这里有两个问题。我有一组文件,它们通常是带有BOM的UTF-8。我想把它们转换成没有BOM的UTF-8 (最好是就地)。看起来codecs.StreamRecoder(stream, encode, decode, Reader, Writer, errors)会处理这件事。但我真的看不到任何关于用法的好例子。这是处理这个问题的最好方法吗?

代码语言:javascript
复制
source files:
Tue Jan 17$ file brh-m-157.json 
brh-m-157.json: UTF-8 Unicode (with BOM) text

此外,如果我们可以在不明确知道的情况下处理不同的输入编码(参见ASCII和UTF-16),那将是最理想的。看起来这一切都应该是可行的。有没有一个解决方案可以接受任何已知的Python编码和输出为UTF-8而不需要BOM?

从下面编辑1个提议的解决方案(谢谢!)

代码语言:javascript
复制
fp = open('brh-m-157.json','rw')
s = fp.read()
u = s.decode('utf-8-sig')
s = u.encode('utf-8')
print fp.encoding  
fp.write(s)

这会给我以下错误:

代码语言:javascript
复制
IOError: [Errno 9] Bad file descriptor

新闻快讯

我在评论中被告知,错误是我以'rw‘模式打开文件,而不是'r+'/'r+b',所以我最终应该重新编辑我的问题并删除已解决的部分。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2012-01-18 00:47:57

只需使用"utf-8-sig" codec

代码语言:javascript
复制
fp = open("file.txt")
s = fp.read()
u = s.decode("utf-8-sig")

这将为您提供一个不带物料清单的unicode字符串。然后,您可以使用

代码语言:javascript
复制
s = u.encode("utf-8")

将一个普通的UTF8编码的字符串返回到s。如果你的文件很大,那么你应该避免将它们全部读入内存。BOM在文件的开头只有三个字节,因此您可以使用以下代码将它们从文件中剥离出来:

代码语言:javascript
复制
import os, sys, codecs

BUFSIZE = 4096
BOMLEN = len(codecs.BOM_UTF8)

path = sys.argv[1]
with open(path, "r+b") as fp:
    chunk = fp.read(BUFSIZE)
    if chunk.startswith(codecs.BOM_UTF8):
        i = 0
        chunk = chunk[BOMLEN:]
        while chunk:
            fp.seek(i)
            fp.write(chunk)
            i += len(chunk)
            fp.seek(BOMLEN, os.SEEK_CUR)
            chunk = fp.read(BUFSIZE)
        fp.seek(-BOMLEN, os.SEEK_CUR)
        fp.truncate()

它打开文件,读取一个块,并将其写出到文件中,比读取它的位置早3个字节。该文件将被就地重写。因为更简单的解决方案是将较短的文件写入一个新文件,如newtover's answer。这会更简单,但在短时间内使用两倍的磁盘空间。

至于猜测编码,那么您可以从最具体到最不具体依次遍历编码:

代码语言:javascript
复制
def decode(s):
    for encoding in "utf-8-sig", "utf-16":
        try:
            return s.decode(encoding)
        except UnicodeDecodeError:
            continue
    return s.decode("latin-1") # will always work

UTF-16编码的文件不能解码为UTF-8,因此我们首先尝试使用UTF-8。如果失败,那么我们尝试使用UTF-16。最后,我们使用拉丁-1-这将始终有效,因为所有256个字节都是拉丁-1中的合法值。在这种情况下,您可能希望返回None,因为它实际上是一种后备,并且您的代码可能希望更小心地处理这一点(如果可以)。

票数 138
EN

Stack Overflow用户

发布于 2015-10-23 10:57:04

在Python3中很简单:读取文件并使用utf-8编码重写它:

代码语言:javascript
复制
s = open(bom_file, mode='r', encoding='utf-8-sig').read()
open(bom_file, mode='w', encoding='utf-8').write(s)
票数 71
EN

Stack Overflow用户

发布于 2012-01-18 01:03:45

代码语言:javascript
复制
import codecs
import shutil
import sys

s = sys.stdin.read(3)
if s != codecs.BOM_UTF8:
    sys.stdout.write(s)

shutil.copyfileobj(sys.stdin, sys.stdout)
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8898294

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档