《Python Cookbook(第2版)中文版》——1.23 对Unicode数据编码并用于XML和HTML

    xiaoxiao2024-06-05  109

    本节书摘来自异步社区《Python Cookbook(第2版)中文版》一书中的第1章,第1.23节,作者[美]Alex Martelli , Anna Martelli Ravenscrof , David Ascher ,高铁军 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。

    1.23 对Unicode数据编码并用于XML和HTML

    任务

    你想对Unicode文本进行编码,使用一种有限制,但很流行的编码,如ASCII或Latin-1,并将处理后的结果用于HTML输出或者某些XML应用。

    解决方案

    Python提供了一种编码错误处理工具,叫做xmlcharrefreplace,它会将所有不属于所选编码的字符用XML的数字字符引用来替代:

    def encode_for_xml(unicode_data, encoding='ascii'): return unicode_data.encode(encoding, 'xmlcharrefreplace')

    也可以将此法用于HTML输出,不过你可能会更喜欢HTML的符号实体引用。出于这个目的,需要定义并注册一个自定义的编码错误处理函数。要实现这样一个处理函数非常简单,因为Python标准库已经提供了一个叫做htmlentitydefs的模块,包含了所有的HTML实体定义:

    import codecs from htmlentitydefs import codepoint2name def html_replace(exc): if isinstance(exc, (UnicodeEncodeError, UnicodeTranslateError)): s = [ u'&%s;' % codepoint2name[ord(c)] for c in exc.object[exc.start:exc.end] ] return ''.join(s), exc.end else: raise TypeError("can't handle %s" % exc._ _name_ _) codecs.register_error('html_replace', html_replace)

    注册完错误处理函数之后,可以再写个包装函数,以简化使用:

    def encode_for_html(unicode_data, encoding='ascii'): return unicode_data.encode(encoding, 'html_replace')

    讨论

    如同其他的一些Python模块一样,这个模块也将提供一个测试的示例,由if _name == ' main _'这一行语句进行保护:

    if _ _name_ _ == '_ _main_ _': # demo data = u'''\ <html> <head> <title>Encoding Test</title> </head> <body> <p>accented characters: <ul> <li>\xe0 (a + grave) <li>\xe7 (c + cedilla) <li>\xe9 (e + acute) </ul> <p>symbols: <ul> <li>\xa3 (British pound) <li>\u20ac (Euro) <li>\u221e (infinity) </ul> </body></html> ''' print encode_for_xml(data) print encode_for_html(data)

    如果将此模块作为主脚本来运行,你会看到如下的输出(来自于encode_for_xml):

    <li>à (a + grave) <li>ç (c + cedilla) <li>é (e + acute) ... <li>£ (British pound) <li>€ (Euro) <li>∞ (infinity)

    还有这些(来自于encode_for_html):

    <li>à (a + grave) <li>ç (c + cedilla) <li>é (e + acute) ... <li>£ (British pound) <li>€ (Euro) <li>∞ (infinity)

    这两段输出都很清晰,不过encode_for_xml更加具有通用性(它可以用于任何XML应用,不仅仅是HTML),但encode_for_html却能够生成更易读的结果—如果希望直接读取或者编辑那些结果。如果给浏览器提供这两种形式的数据,能够看到渲染输出实际上是一样的。为了看到这两种方式在浏览器中的展示,可以将上述代码作为主脚本运行,将输出导向到一个磁盘文件,并用文本编辑器将这两种输出分隔开来,然后用浏览器分别查看。(再或者,运行脚本两次,一次将调用encode_for_xml的输出注释掉,一次将encode_for_html的输出注释掉)。

    请记住,Unicode数据在被打印或者写到文件之前一定要先编码。由于UTF-8能够处理任何Unicode字符,所以它是理想的编码。但对很多用户和应用而言,ASCII或Latin-1比UTF-8更受欢迎。当Unicode数据包含了指定编码之外的字符时(比如,一些重音字符和很多符号大多不在ASCII或Latin-1之中,比如,Latin-1无法表现“无穷”符号),单靠这些编码本身,根本无法处理这些数据。Python提供一个内建的编码错误处理函数,叫做xmlcharrefreplace,将所有的不能被编码的字符替换为XML的数字字符引用,比如“∞”,表示“无穷”符号。本节还展示了怎样编写和注册另一个类似的错误处理函数html_replace,针对HTML输出进行处理。html_replace将不能编码的字符替换为更具可读性的HTML符号实体引用,比如用“∞”来表示“无穷”符号。html_replace相比于xmlcharrefreplace,它的通用性没那么好,因为它并不支持所有的Unicode字符,同时也不能用于非HTML的应用;但如果你希望HTML输出的源码文件能够具有更好的可读性,html_replace是非常有用的。

    如果输出的不是HTML或者任何形式的XML,这些错误处理函数就没什么意义了。比如,TeX和其他的标记语言并不认识XML的数字字符引用,但如果你知道怎样创建一个该标记语言中的字符引用,可以修改本节示例中的错误处理函数html_replace,并注册一个新的符合需求的处理函数。

    当需要将Unicode数据写入文件时,可以使用Python标准库的codecs模块提供的另一个(非常高效)可以指定编码和错误处理函数的方法:

    outfile = codecs.open('out.html', mode='w', encoding='ascii', errors='html_replace')

    现在,可以将outfile.write(unicode_data)应用于任何Unicode字符串unicode_data,所有的编码和错误处理都会透明地自动进行。当然,在输出完成之后,还得调用outfile.close()。

    相关资源:Python Cookbook
    最新回复(0)