在Python中设置sax解析器的编码

Dan*_*ver 6 python unicode sax

当我将utf-8编码的xml提供给ExpatParser实例时:

def test(filename):
    parser = xml.sax.make_parser()
    with codecs.open(filename, 'r', encoding='utf-8') as f:
        for line in f:
            parser.feed(line)
Run Code Online (Sandbox Code Playgroud)

......我得到以下内容:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "test.py", line 72, in search_test
    parser.feed(line)
  File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/xml/sax/expatreader.py", line 207, in feed
    self._parser.Parse(data, isFinal)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xb4' in position 29: ordinal not in range(128)
Run Code Online (Sandbox Code Playgroud)

我可能在这里遗漏了一些明显的东西.如何将解析器的编码从"ascii"更改为"utf-8"?

Ste*_*202 5

您的代码在Python 2.6中失败,但在3.0中有效.

这在2.6中有效,大概是因为它允许解析器本身找出编码(可能通过读取XML文件第一行上可选的编码,否则默认为utf-8):

def test(filename):
    parser = xml.sax.make_parser()
    parser.parse(open(filename))
Run Code Online (Sandbox Code Playgroud)


Jar*_*die 5

Python 2.6中的SAX解析器应该能够解析utf-8而不会破坏它.虽然您已经省略了与解析器一起使用的ContentHandler,但如果该内容处理程序尝试将任何非ascii字符打印到您的控制台,则会导致崩溃.

例如,假设我有这个XML文档:

<?xml version="1.0" encoding="utf-8"?>
<test>
   <name>Champs-Élysées</name>
</test>
Run Code Online (Sandbox Code Playgroud)

而这个解析装置:

import xml.sax

class MyHandler(xml.sax.handler.ContentHandler):

    def startElement(self, name, attrs):
        print "StartElement: %s" % name

    def endElement(self, name):
        print "EndElement: %s" % name

    def characters(self, ch):
        #print "Characters: '%s'" % ch
        pass

parser = xml.sax.make_parser()
parser.setContentHandler(MyHandler())

for line in open('text.xml', 'r'):
    parser.feed(line)
Run Code Online (Sandbox Code Playgroud)

这将解析得很好,内容将确实保留XML中的重音字符.唯一的问题就是def characters()我已经注释掉的那条线.在Python 2.6中运行在控制台中,这将产生您看到的异常,因为print函数必须将字符转换为ascii以进行输出.

您有3种可能的解决方案:

:确保终端支持unicode,然后sitecustomize.py在您的终端中创建一个条目site-packages并将默认字符集设置为utf-8:

import sys sys.setdefaultencoding('utf-8')

:不要将输出打印到终端(诙谐)

:使用unicodedata.normalize将非ascii字符转换为ascii等效值或encode将字符转换为ascii进行文本输出来标准化输出:ch.encode('ascii', 'replace').当然,使用此方法您将无法正确评估文本.

使用上面的选项1,您的代码在我的Python 2.5中运行得很好.


小智 5

Jarret Hardie已经解释了这个问题.但是那些正在编写命令行的人,并且似乎没有"sys.setdefaultencoding"可见,快速解决这个bug(或"功能")是:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
Run Code Online (Sandbox Code Playgroud)

希望reload(sys)不会破坏其他任何东西.

这个旧博客的更多细节:

Illusive setdefaultencoding