【问题标题】:How to convert a CP949 RTF to a UTF-8 encoded RTF?如何将 CP949 RTF 转换为 UTF-8 编码的 RTF?
【发布时间】:2013-12-24 02:36:32
【问题描述】:

我想编写一个 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'”是什么意思?
  • terms_utf.rtf 不编码为 utf-8
  • 该响应没有比原始问题更多的信息。
  • 即使在编辑之后,“这并没有按照我的预期改变编码”是什么意思?如果你无法解释,给我们举个例子:一个非常短的 RTF 文件,它出现在你的编辑器中,其中的实际字节例如 hexdump,然后是你的代码产生的实际字节,以及你预计它会改为生产。

标签: python encoding utf-8 rtf


【解决方案1】:

共有三种 RTF,我不知道你有哪一种。 可以通过在纯文本编辑器中打开文件来判断,或者只是使用less/more/cat/type/whatever 将其打印到您的终端。


首先,简单的案例:明文 RTF。

纯文本 RTF 文件以 {\rtf 开头,其中的所有文本都是(正如您所期望的)纯文本 - 尽管有时文本运行会使用格式化命令分成单独的运行 - 以\——在他们之间。由于所有格式化命令都是纯 ASCII,如果您将纯文本 RTF 从一个字符集转换为另一个字符集(只要两者都是 ASCII 的超集,如 cp949 和 utf-8 都是),它应该可以正常工作。

但是,该文件也可能有一个格式化命令,用于指定写入的字符集。该命令类似于\ansicpg949。当像写字板这样的 RTF 编辑器打开您的文件时,它会将您所有漂亮的 UTF-8 数据解释为 cp949 数据,并且除非您修复它,否则它会被 mojibake 搞砸。

解决此问题的最简单方法是找出您的编辑器想要为 UTF-8 文件放置的字符集。也许是\ansicpg65001,也许是\utf8,也许是完全不同的东西。所以只需将一个简单的文件保存为 UTF-8 RTF,然后用纯文本查看 it,看看它有什么代替 \ansicpg949,然后用右边的替换文件中的字符串一。 (请注意,代码页 65001 并不是真正 UTF-8,但它很接近,而且许多 Microsoft 代码都假定它们是相同的……)

此外,一些 RTF 编辑器(如 Apple 的 TextEdit)会转义任何非 ASCII 字符(例如,é 存储为 \'e9),因此无需转换。

最后,Office Open XML 包含一个用于称为 RTF 的 XML 规范,但实际上并不是一回事。我相信很多 RTF 编辑器都可以处理这个问题。幸运的是,您可以像对待纯文本 RTF 一样对待它——所有 XML 标记都有纯 ASCII 名称。


最简单的情况是压缩的纯文本 RTF。这是同一件事,但我相信是用 zlib 压缩的。或者它实际上可以是 .zip 存档中的 RTFD(可以是纯文本 RTF 以及单独文件中的图像和其他内容,或实际纯文本格式运行存储在单独文件中)。无论如何,如果你有其中之一,大多数Unix系统上的file命令应该能够将其检测为“压缩RTF”,此时我们可以弄清楚具体格式是什么并解压它,然后你就可以将其编辑为纯文本 RTF(或 RTFD)。

不用说,如果您不先解压缩此文件,您将不会在文件中看到任何您熟悉的文本 - 您很容易最终破坏它,因此无法解压缩,或者解压缩为垃圾, 通过将任意字节更改为不同的字节。


最后,困难的情况:二进制 RTF。

尽管它们已经过逆向工程,但它们的最早版本采用无证格式。以后的版本是公共规格。 Wikipedia 有规格链接。如果你想手动解析它,你可以,但它会是大量的代码,你将不得不自己编写。

更好的解决方案是使用one of the many libraries on PyPI,它可以将 RTF(包括二进制 RTF)转换为其他格式,然后您可以轻松编辑。

【讨论】:

  • 文件以'{\rtf1\ansi\ansicpg949\ ... {*\generator Msftedit 5.41.21.2510;}'开头
  • @ArenaSon:那么这是一个纯文本 RTF,所以你很幸运。你不明白我的解释吗?
【解决方案2】:
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() 是什么?如果这给你的不是垃圾,那你就是地球上最幸运的人。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-03
  • 1970-01-01
  • 1970-01-01
  • 2017-07-18
  • 1970-01-01
  • 1970-01-01
  • 2010-10-01
相关资源
最近更新 更多