在Python 2.7中,Unicode文本显示为u'xxxx而非日语

2 投票
1 回答
1183 浏览
提问于 2025-04-21 05:15

我在使用Python处理很多日文文本文件时,遇到了很多关于Unicode的问题。我知道可以用.encode("utf-8")把日文文本从u'xxxx的格式转换回正常的日文显示。我没有遇到任何编码或解码的错误。但是,我从一个Unicode文件读取文本,处理后再写入新文件时,文本却变成了u'xxxx这样的字符串,而不是原来的日文。我在多个地方尝试过使用.encode()和.decode(),也试过不使用它们,但每次结果都是一样的。欢迎任何建议。

具体来说,我在使用Scrapy库写一个爬虫,它从一个文件中提取文本,构建新文件的文件名,然后把HTML文件的第一个div内容作为字符串写入那个新文件。

让我更困惑的是,我用来创建文件名的文本片段都是正常显示为日文,文件名本身也是日文。难道是因为我在div上使用了str(),所以文件内容变成了u'xxxx吗?请查看代码的最后部分。

这是我的完整代码(请忽略其中一些比较糟糕的部分):

def parse_item(self, response):
    original = 0
    author = "noauthor"
    title = "notitle"
    year = "xxxx"
    publisher = "xxxx"
    typer = "xxxx"
    ispub = 0
    filename = response.url.split("/")[-1]
    if "_" in filename:
        filename = filename.split("_")[0]
        if filename.isdigit():
            title = response.xpath("//h1/text()").extract()[0].encode("utf-8")
            author = response.xpath("//h2/text()").extract()[0].encode("utf-8")
            ID = filename
            bibliographic_info = response.xpath("//div[2]/text()").extract()
            for subyear in bibliographic_info:
                ispub = 0
                subyear = subyear.encode("utf-8").strip()
                if "初出:" in subyear:
                    publisher = subyear.split(":")[1]
                    original = 1
                    ispub = 1
                if "入力:" in subyear:
                    typer = subyear.split(":")[1]
                if len(subyear) > 1 and (original == 1) and (ispub == 0):
                    counter = 0
                    while counter < len(subyear):
                        if subyear[counter].isdigit():
                            break
                        counter+=1
                    if counter != len(subyear):
                        year = subyear[counter:(counter+4)]
                    original = 0
    body = str(response.xpath("//div[1]/text()").extract())
    new_filename = author + "_" + title + "_" + publisher + "_" + year + "_" + typer + ".html"
    file = open(new_filename, "a")
    file.write(body.encode("utf-8")  
    file.close()

1 个回答

3
# -*- coding: utf-8 -*-
# u'初出' and u'\u521d\u51fa' are different ways to specify *the same* string
assert u'初出' == u'\u521d\u51fa'
#XXX don't mix Unicode and bytes!!!
assert u'初出' != '初出' and u'初出' != '\u521d\u51fa' 

不要在处理Unicode字符串时使用str(),而是应该使用.encode()这个方法。除非必要,不要随便调用.encode().decode();可以使用一种叫做Unicode三明治的方法:

  • 把从外部接收到的字节解码成Unicode格式
  • 在你的代码里保持使用Unicode格式
  • 最后在保存到文件或通过网络发送之前,再把它编码成字节

第一步和最后一步可能是隐含的,也就是说,你的程序可能只会看到Unicode文本。

需要注意的是,这里有三件不同的事情:

  • 在源代码中用字符串字面量指定字符串时,它的样子(比如Unicode转义、源代码编码、原始字符串字面量)
  • 字符串的内容
  • 如果你打印出来,它的样子(repr(),'backslashreplace'错误处理器)

如果你在输出中看到u'...',这意味着在某个时刻调用了repr(unicode_string)。这可能是隐含的,比如通过print([unicode_string]),因为在把列表转换成字符串时,会对列表中的每个项目调用repr()

print(u'\u521d\u51fa')       # -> 初出 #NOTE: no u'', \u..
print(repr(u'\u521d\u51fa')) # -> u'\u521d\u51fa'

撰写回答