在Python中设置sax解析器的编码
当我将utf-8编码的xml提供给解析器实例时:在Python中设置sax解析器的编码,python,unicode,sax,Python,Unicode,Sax,当我将utf-8编码的xml提供给解析器实例时: 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) …我得到以下信息: Traceback (most recent call last): File "<
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)
…我得到以下信息:
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)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“test.py”,第72行,在搜索测试中
提要(行)
文件“/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/xml/sax/expatreader.py”,第207行,在提要中
self.\u parser.Parse(数据,isFinal)
UnicodeEncodeError:“ascii”编解码器无法对位置29中的字符u'\xb4'进行编码:序号不在范围内(128)
我可能错过了一些明显的东西。如何将解析器的编码从“ascii”更改为“utf-8”?您的代码在Python 2.6中失败,但在3.0中可以工作 这在2.6中确实起作用,可能是因为它允许解析器自己找出编码(可能是通过读取XML文件第一行上可选指定的编码,或者默认为utf-8):
Python2.6中的SAX解析器应该能够解析utf-8而不会损坏它。虽然您省略了解析器使用的ContentHandler,但如果该内容处理程序试图将任何非ascii字符打印到控制台,则会导致崩溃 例如,假设我有这个XML文档:
<?xml version="1.0" encoding="utf-8"?>
<test>
<name>Champs-Élysées</name>
</test>
这将很好地解析,并且内容将确实保留XML中的重音字符。唯一的问题是我注释掉的def characters()
中的那一行。在Python2.6的控制台中运行,这将产生您看到的异常,因为print函数必须将字符转换为ascii进行输出
您有3种可能的解决方案:
One:确保您的终端支持unicode,然后在网站包中创建sitecustomize.py
条目,并将默认字符集设置为utf-8:
def test(filename):
parser = xml.sax.make_parser()
parser.parse(open(filename))
导入系统
sys.setdefaultencoding('utf-8')
Two:不要将输出打印到终端(开玩笑)
Three:使用Unicode数据对输出进行规格化。规格化将非ascii字符转换为ascii等效字符,或将字符编码为ascii进行文本输出:ch.encode('ascii',replace')
。当然,使用此方法无法正确评估文本
使用上面的选项一,您的代码在Python2.5中的my中运行良好。Jarret Hardie已经解释了这个问题。但是,对于那些正在为命令行编码并且似乎没有“sys.setdefaultencoding”可见的人来说,解决此错误(或“功能”)的快速方法是:
希望reload(sys)
不会破坏其他任何东西
此旧博客中的更多详细信息:
在评论janpf的回答时(对不起,我没有足够的声誉将其放在那里),请注意janpf的版本将中断空闲,这需要它自己的标准输出等。这与sys的默认设置不同。因此,我建议将代码修改为:
import sys
currentStdOut = sys.stdout
currentStdIn = sys.stdin
currentStdErr = sys.stderr
reload(sys)
sys.setdefaultencoding('utf-8')
sys.stdout = currentStdOut
sys.stdin = currentStdIn
sys.stderr = currentStdErr
可能还有其他变量需要保留,但它们似乎是最重要的。要为SAX解析器设置任意文件编码,可以使用以下方法:
def test(filename, encoding):
parser = xml.sax.make_parser()
with open(filename, "rb") as f:
input_source = xml.sax.xmlreader.InputSource()
input_source.setByteStream(f)
input_source.setEncoding(encoding)
parser.parse(input_source)
这允许解析具有非ASCII、非UTF8编码的XML文件。例如,可以解析用拉丁语编码的扩展ASCII文件,如:test(文件名,“拉丁语”)
(添加此答案是为了直接解决此问题的标题,因为它往往在搜索引擎中排名很高。)原始问题中的实际问题与将unicode打印到终端无关。正如Stephan202所指出的,这是由于OP使用codecs.open对输入进行了预解码。
import sys
currentStdOut = sys.stdout
currentStdIn = sys.stdin
currentStdErr = sys.stderr
reload(sys)
sys.setdefaultencoding('utf-8')
sys.stdout = currentStdOut
sys.stdin = currentStdIn
sys.stderr = currentStdErr
def test(filename, encoding):
parser = xml.sax.make_parser()
with open(filename, "rb") as f:
input_source = xml.sax.xmlreader.InputSource()
input_source.setByteStream(f)
input_source.setEncoding(encoding)
parser.parse(input_source)