Python,.format()和UTF-8

Mat*_*eod 7 python unicode beautifulsoup

我的背景是在Perl中,但我正在尝试使用Python和BeautifulSoup来尝试新项目.

在这个例子中,我试图提取并呈现单个页面中包含的链接目标和链接文本.这是来源:

table_row = u'<tr><td>{}</td><td>{}</td></tr>'.encode('utf-8')
link_text = unicode(link.get_text()).encode('utf-8')
link_target = link['href'].encode('utf-8')
line_out = unicode(table_row.format(link_text, link_target))
Run Code Online (Sandbox Code Playgroud)

所有那些对.encode('utf-8')的显式调用都是我尝试使这个工作,但它们似乎没有帮助 - 我可能完全误解了Python 2.7如何处理Unicode字符串.

无论如何.这很好用,直到它在URL中遇到U + 2013(是的,真的).那时它爆炸了:

Traceback (most recent call last):
File "./test2.py", line 30, in <module>
  line_out = unicode(table_row.encode('utf-8').format(link_text, link_target.encode('utf-8')))
  UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 79: ordinal not in range(128)
Run Code Online (Sandbox Code Playgroud)

据推测,.format(),甚至应用于Unicode字符串,正在玩愚蠢的bug并试图进行.decode()操作.由于ASCII是默认值,它正在使用它,当然它无法将U + 2013映射到ASCII字符,因而......

选项似乎是删除它或将其转换为其他东西,但我真正想要的只是保留它.最终(这只是一个小测试案例)我需要能够提供可用的可点击链接.

BS3文档建议将默认编码从ASCII更改为UTF-8,但是阅读类似问题的评论看起来非常糟糕,因为它会破坏字典.

如果没有使用Python 3.2(这意味着没有Django,我们正在考虑这个项目的一部分)是否有一些方法可以使这项工作干净利落?

Ned*_*der 10

首先,请注意您的两个代码示例在有问题的行的文本上不一致:

line_out = unicode(table_row.encode('utf-8').format(link_text, link_target.encode('utf-8')))
Run Code Online (Sandbox Code Playgroud)

VS

line_out = unicode(table_row.format(link_text, link_target))
Run Code Online (Sandbox Code Playgroud)

第一个是追溯中的那个,所以它是要看的那个.假设您的第一个代码示例的其余部分是准确的,table_row是一个字节字符串,因为您使用了一个unicode字符串并对其进行了编码.字节字符串无法编码,因此Python 2将table_row从字节字符串隐式转换为unicode,方法是将其解码为ascii.因此错误消息"来自ascii的UnicodeDecodeError".

您需要确定哪些字符串将是字节字符串,哪些字符串将是unicode字符串,并对其进行管理.我建议尽可能将所有文本保留为Unicode字符串.

这是我在PyCon上给出的一个演示文稿,它解释了一切:实用的Unicode,或者,我如何阻止痛苦?