【问题标题】:How to read Chinese files?如何阅读中文文件?
【发布时间】:2016-07-28 23:18:34
【问题描述】:

我被所有这些令人困惑的编码东西所困扰。我有一个包含中文字幕的文件。我实际上相信它是 UTF-8,因为在 Notepad++ 中使用它会给我带来非常好的结果。如果我设置gb2312,中文部分还是可以的,但是我会看到一些UTF8代码没有被转换。

目标是遍历文件中的文本并计算不同字符出现的次数。

import os
import re
import io

character_dict = {}
for dirname, dirnames, filenames in os.walk('.'):
    for filename in filenames:
        if "srt" in filename:
            import codecs
            f = codecs.open(filename, 'r', 'gb2312', errors='ignore')
            s = f.read()

            # deleting {}
            s = re.sub('{[^}]+}', '', s)
            # deleting every line that does not start with a chinese char
            s = re.sub(r'(?m)^[A-Z0-9a-z].*\n?', '', s)
            # delete non chinese chars
            s = re.sub(r'[\s\.A-Za-z0-9\?\!\\/\-\"\,\*]', '', s)
            #print s
            s = s.encode('gb2312')
            print s
            for c in s:
                #print c
                pass

这实际上会给我完整的中文文本。但是当我打印出底部的循环时,我只会得到问号而不是单个字符。

还要注意我说它是 UTF8,但我必须使用 gb2312 进行编码并作为我的 gnome 终端中的设置。如果我在代码中将其设置为 UTF8,无论我将终端设置为 UTF8 还是 gb2312,我都会得到垃圾。所以也许这个文件毕竟不是 UTF8 的!?

在任何情况下s都包含完整的中文文本。为什么不能循环播放?

请帮助我理解这一点。这对我来说非常困惑,文档让我无处可去。谷歌只是引导我解决有人解决的类似问题,但到目前为止还没有任何解释可以帮助我理解这一点。

【问题讨论】:

  • 那么是gb2312还是UTF-8?如果是 UTF-8,为什么不将编码设置为open() 而不是gb2312?。就目前而言,这个问题没有多大意义
  • 不是 UTF-8,它是GB2313。 UTF-8 和 GB2313 都是 encodings,一种将字符编码为字节的方法。您是否将 UTF-8 与 Unicode 标准混淆了?
  • 是的,@MartijnPieters - 我知道区别,我也知道它们是针对不同字符集的编码。 OP 似乎可以互换使用这两种编码/字符集>“我实际上相信它是 UTF-8,因为在 Notepad++ 中使用它会给我带来非常好的结果。”
  • @JasonTS,你不应该改变你的终端的编码而不改变你的locale。 Python 将使用您的语言环境来计算调用 print 时要使用的编码。
  • @AlastairMcCormack:我的评论不是针对你的。 :-)

标签: python unicode utf-8 chinese-locale


【解决方案1】:

gb2312 是一种多字节编码。如果你迭代一个用它编码的字节串,你将迭代字节,而不是你想要计数(或打印)的字符。您可能希望在编码之前对 unicode 字符串进行迭代。如有必要,您可以将各个代码点(字符)编码为它们自己的字节串以进行输出:

# don't do s = s.encode('gb2312')
for c in s:      # iterate over the unicode codepoints
    print c.encode('gb2312')  # encode them individually for output, if necessary

【讨论】:

  • 谢谢你终于成功了!我现在可以将它们用作 dict 键吗?
  • 是的,您可以将循环中的c 代码点用作字典键。我想你也可以使用它们的编码版本,但我认为没有一个很好的理由这样做。最好在程序中的任何地方对文本使用 unicode 对象,除非您必须对内容进行编码以使 IO 正常工作(例如,读取或写入文件或网络数据,或打印到控制台)。
【解决方案2】:

您正在打印单个字节。 GB2312是多字节编码,每个codepoint使用2个字节。单独打印这些字节不会产生有效的输出,不会。

解决方案是打印时不要从 Unicode 编码为字节。而是循环遍历 Unicode 字符串:

# deleting {}
s = re.sub('{[^}]+}', '', s)
# deleting every line that does not start with a chinese char
s = re.sub(r'(?m)^[A-Z0-9a-z].*\n?', '', s)
# delete non chinese chars
s = re.sub(r'[\s\.A-Za-z0-9\?\!\\/\-\"\,\*]', '', s)
#print s

# No `s.encode()`!
for char in s:
    print char

可以单独编码每个char 字符:

for char in s:
    print char

但是,如果您正确配置了控制台/IDE/终端,您应该能够直接打印而不会出错,尤其是因为您的 print s.encode('gb2312)` 会产生正确的输出。

您似乎还混淆了UTF-8(一个编码)和Unicode standard。 UTF-8 可用于以字节表示 Unicode 数据。 GB2312 也是一种编码,可用于表示以字节为单位的 Unicode 文本(子集)。

您可能想了解 Python 和 Unicode:

【讨论】:

  • 感谢您的帮助。然而,这会导致“UnicodeEncodeError: 'ascii' codec can't encode character u'\u73b0' in position 0: ordinal not in range(128)”知道问题可能是什么吗?
  • @JasonTS:你要打印什么?您的终端似乎被错误地配置为仅接受 ASCII,但您的 print s.encode('gb2312') 工作表明它改为接受 GB2312。
  • @JasonTS:您可以使用 print char.encode('gb2312') 手动编码,但您最好修复终端区域设置。或者这是一个 IDE 控制台还是 Windows?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多