在 python 中使用 XML 中的 unicode 字符:'ascii'编解码器无法对位置 0-3 中的字符进行编码:序号不在范围内(128)



我使用 django,在我看来,我需要以 XML 格式发送一个请求,其中包含一些 unicode 字符,该请求使用 post 方法从 html 页面接收。我尝试了这些(请注意,我将该输入保存在 fname 变量中):

xml = r"""my XML code with unicode {0} """.format(fname)

fname = u"%s".encode('utf8') % (fname)
xml = r"""my XML code with unicode {0} """.format(fname)

fname = fname.encode('ascii', 'ignore').decode('ascii')
xml = r"""my XML code with unicode {0} """.format(fname)

每次我收到此错误时:

'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)

您可以使用以下代码重现错误:

>>> "{0}".format(u"U0001F384"*4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)

要修复此特定错误,只需使用 Unicode 格式字符串:

>>> u"{0}".format(u"U0001F384"*4)
u'U0001f384U0001f384U0001f384U0001f384'

您可以使用xml.etree.ElementTree模块来构建xml文档,而不是字符串格式.xml这是一种复杂的格式;很容易出错。 ElementTree还会将 Unicode 字符串正确序列化为字节,以确保 xml 声明中的字符编码与文档中使用的实际编码一致。

xml = r"""my XML code with unicode {0} """.format(fname)

.format 方法始终生成与输入格式字符串相同的输出字符串类型。如果你的格式字符串是一个字节字符串r"""..."""所以如果fname是一个Unicode字符串,Python试图强制它成为一个字节字符串。如果frame包含默认编码 (ASCII) 中不存在的字符,则 bang。

请注意,这与旧的字符串格式化运算符 % 不同,当格式字符串或使用的任何参数为 Unicode 时,它尝试提升为 Unicode 字符串,只要my XML code与 ASCII 兼容,在这种情况下就可以工作。这是将使用%的代码转换为.format()时出现的常见问题。

这应该可以正常工作:

xml = ur"""my XML code with unicode {0} """.format(fname)

但是,输出将是一个 Unicode 字符串,因此无论您接下来做什么都需要处理它(例如,如果您将其写入字节流/文件,您可能希望.encode('utf-8')整个事情)。或者,就地对其进行编码以获取字节字符串:

xml = r"""my XML code with unicode {0} """.format(fname.encode('utf-8'))

请注意,上面是:

fname = u"%s".encode('utf8') % (fname)

不起作用,因为您将格式字符串编码为字节,而不是fname参数。这与只说fname = '%s' % fname相同,这实际上是fname = fname

我用这段代码解决了这个问题:

fname = fname.encode('ascii', 'xmlcharrefreplace')

这闻起来很臭。对于输入hello ☃,您现在正在生成hello &#9731;而不是正常的输出hello ☃

如果&#9731;在输出中看起来相同,那么您可能正在执行以下操作:

xml = '<element>{0}</element>'.format(some_text)

对于 XML 特殊字符(如 &<)会损坏。当你生成XML时,你应该注意转义特殊字符(&<>"'&amp;&lt;等),否则你的输出充其量会因为这些字符而中断; 在最坏的情况下,当some_text包含用户输入时,您会遇到一个 XML 注入漏洞,该漏洞可能会以安全老化的方式破坏系统的逻辑。

正如 J F Sebastian 所说 (+1),最好使用现有的已知良好的 XML 序列化库(如 etree),而不是尝试自己创建。

你可以做这样的事情:

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

但它是一个丑陋的黑客,只适用于Python 2.7。

fname.encode('GB18030').decode('utf-8')

它将绕过错误,但可能仍然看起来很混乱。如果您要发布到 html 文件,则使字符集 utf-8

我用这段代码解决了这个问题:

fname = fname.encode('ascii', 'xmlcharrefreplace')
xml = r"""my XML code with unicode {0} """.format(fname)

谢谢你的帮助。

更新:你可以用这个删除或替换像>和<这样的特殊字符(感谢@bobince注意这一点):>

fname = fname.replace("<", "")
fname = fname.replace(">", "")
fname = fname.replace("&", "")

最新更新