如何将CP949格式的RTF转换为UTF-8编码的RTF?

5

我想编写一个Python脚本,将文件编码从cp949转换为utf8。该文件最初是以cp949编码的。 我的脚本如下:

cpstr = open('terms.rtf').read()  
utfstr = cpstr.decode('cp949').encode('utf-8')  
tmp  = open('terms_utf.rtf', 'w')  
tmp.write(utfstr)  
tmp.close()

但这并没有按照我的意愿改变编码方式。

首先,你说的“仍然‘cp949’”是什么意思? - abarnert
terms_utf.rtf没有以utf-8编码 - Arena Son
该响应没有比原始问题更多的信息。 - abarnert
即使编辑后,你说的“这不是我想要的编码方式”仍然存在疑问。如果你无法解释清楚,请给我们提供一个例子:一个非常短的RTF文件,它在你的编辑器中的样子,以及其中的实际字节,比如十六进制转储,然后是你的代码生成的实际字节,以及你所期望的代替品。 - abarnert
2个回答

11
有三种RTF格式,我不知道你使用的是哪一种。你可以通过在纯文本编辑器中打开文件或者使用less/more/cat/type等命令将其输出到终端来确定。
首先,简单情况:纯文本RTF。
纯文本RTF文件以{\rtf开始,其中的所有文本都是纯文本,虽然有时文本块会被分成带有格式命令的单独块——命令以\开头。由于所有格式命令都是纯ASCII,如果您将纯文本RTF从一种字符集转换为另一种(只要两者都是ASCII的超集,如cp949和utf-8),它就应该可以正常工作。
但是,文件也可能具有指定所写字符集的格式命令。这个命令看起来像\ansicpg949。当类似WordPad的RTF编辑器打开您的文件时,如果您不进行修复,它将把所有漂亮的UTF-8数据解释为cp949数据并显示乱码。
最简单的方法是弄清楚编辑器想要用哪种字符集来替换UTF-8文件中的\ansicpg949。也许是\ansicpg65001,也许是\utf8,也许是完全不同的东西。因此,只需将一个简单的文件保存为UTF-8 RTF,然后在纯文本中查看它,看看它在\ansicpg949位置放置了什么,然后用正确的字符串替换您的文件中的字符串即可。(请注意,代码页65001不是真正的UTF-8,但它很接近,微软的很多代码都假设它们是相同的...)
此外,一些RTF编辑器(例如Apple的TextEdit)将转义任何非ASCII字符(例如,将é存储为\'e9),因此无需进行转换。最后,Office Open XML包括一个名为RTF的XML规范,但并不是完全相同的东西。我认为许多RTF编辑器都可以处理这个问题。幸运的是,您可以将其视为纯文本RTF一样处理 - 所有XML标记都具有纯ASCII名称。
几乎同样简单的情况是压缩的纯文本RTF。这是相同的东西,但是使用了我认为是zlib的压缩算法,或者它实际上可以是RTFD(可以是单独文件中的纯文本RTF和图像等内容,也可以是在另一个文件中存储格式化运行的实际纯文本)在.zip档案中。无论如何,如果您拥有其中之一,则大多数Unix系统上的file命令应该能够将其检测为“压缩的RTF”,此时我们可以确定特定格式并将其解压缩,然后您可以将其作为纯文本RTF(或RTFD)进行编辑。
不用说,如果您不先解压缩它,则不会在文件中看到任何熟悉的文本,而且通过将任意字节更改为不同的字节,您很容易使其无法解压缩或解压缩为垃圾。
最后一个难点:二进制RTF。
最早的这些版本采用了一种未经记录的格式,尽管它们已被反向工程化。后来的版本是公共规范。Wikipedia上有相关规范的链接。如果您想手动解析它,则可能需要大量的代码,并且您必须自己编写代码。
更好的方法是使用PyPI上的许多库之一,可以将RTF(包括二进制RTF)转换为其他格式,然后您可以轻松编辑。

文件开头为'{\rtf1\ansi\ansicpg949\ ... {*\generator Msftedit 5.41.21.2510;}' - Arena Son
@ArenaSon:那么它就是纯文本RTF,你很幸运。你不明白我的解释吗? - abarnert

-1
import codecs
cpstr = codecs.open('terms.rtf','r','cp949').read()
u = cpstr.encode('cp949').decode('utf-8')
tmp  = open('terms_utf.rtf', 'w') 
tmp.write(u)  
tmp.close()

为什么要将 cp949 解码,然后重新编码为 cp949,再将其解码为 utf-8,最后隐式地重新编码为 sys.getdefaultencoding() 是什么?如果这样做不会得到垃圾数据,那你就是地球上最幸运的人了。 - abarnert

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