当用ssh连接*Nix服务器,几分钟没有操作,ssh连接就会被断开。如何才能保持ssh连接不被超时断开呢?有两种方法:
服务器端设置
打开文件 /etc/ssh/sshd_config 找到 ClientAliveInterval 选项, 如果没有的话,添加此选项。如下设置表示每360秒(6分钟)向客户端发送一个是否保持连接的查询信息(该选项默认为0,表示不发送查询信息)
ClientAliveInterval 360
当用ssh连接*Nix服务器,几分钟没有操作,ssh连接就会被断开。如何才能保持ssh连接不被超时断开呢?有两种方法:
打开文件 /etc/ssh/sshd_config 找到 ClientAliveInterval 选项, 如果没有的话,添加此选项。如下设置表示每360秒(6分钟)向客户端发送一个是否保持连接的查询信息(该选项默认为0,表示不发送查询信息)
ClientAliveInterval 360
| 原文作者: | David Beazley |
|---|---|
| 中文编译: | Tony (digitalsatori) |
>>> for x in [1, 4, 5, 10]: ... print x, ... 1 4 5 10 >>>
>>> prices = { 'GOOG' : 490.10,
... 'AAPL' : 145.23,
... 'YHOO' : 21.71 }
...
>>> for key in prices:
... print key
...
YHOO
GOOG
AAPL
>>>
>>> s = "Yow!" >>> for c in s: ... print c ... Y o w ! >>>
>>> for line in open("real.txt"):
... print line,
...
Real Programmers write in FORTRAN
Maybe they do now,
in this decadent era of
Lite beer, hand calculators, and "user-friendly" software
but back in the Good Old Days,
when the term "software" sounded funny
and Real Computers were made out of drums and vacuum tubesReal Programmers wrote in machine code.
Not FORTRAN. Not RATFOR. Not, even, assembly language.
Machine Code.
Raw, unadorned, inscrutable hexadecimal numbers.
Directly.
消减(Reductions):
sum(s), min(s), max(s)
构造器(Constructors):
list(s), tuple(s), set(s), dict(s)
in 操作符
item in s
以及函数库中众多的其他函数
>>> items = [1, 4, 5]
>>> it = iter(items)
>>> it.next()
1
>>> it.next()
4
>>> it.next()
5
>>> it.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
for x in obj:
# statements
_iter = iter(obj) # 获取枚举器(iterator)对象
while 1:
try:
x = _iter.next() # 获取下一个对象
except StopIteration: # 没有更多的对象了
break
# statements
...
>>> for x in countdown(10): ... print x, ... 10 9 8 7 6 5 4 3 2 1 >>>
class countdown(object):
def __init__(self, start):
self.count = start
def __iter__(self):
return self
def next(self):
if self.count <=0:
raise StopIteration
r = self.count
self.count -= 1
return r
>>> c = countdown(5) >>> for i in c: ... print i, ... ... 5 4 3 2 1 >>>
def countdown(n):
while n > 0:
yield n
n -= 1
>>> for i in countdown(5): ... print i, ... 5 4 3 2 1 >>>
def countdown(n):
print "Counting down from", n
while n > 0:
yield n
n -= 1
>>> x = countdown(10) #注意调用该函数此时并未返回函数中print语句的内容 >>> x <generator object at 0x58490> >>>
>>> x = countdown(10) >>> x <generator object at 0x58490> >>> x.next() Counting down from 10 #函数此时才开始执行 10 >>>
yield 生成的一个值,但立即暂停了函数的运行
>>> x.next() 9 >>> x.next() 8 >>>
>>> x.next()
1
>>> x.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
>>>
>>> a = [1,2,3,4] >>> b = (2*x for x in a) >>> b <generator object at 0x58760> >>> for i in b: print b, ... 2 4 6 8 >>>
该循环遍历一系列的对象并分别处理它们
结果的值是通过generator一次一个生成出来的
举例:
>>> a = [1, 2, 3, 4] >>> b = [2*x for x in a] >>> b [2, 4, 6, 8] >>> c = (2*x for x in a) <generator object at 0x58760> >>>
一般语法:
for j in t if cond2 ... if condfinal)
意思是:
... if condfinal: yield expression
sum(x*x for x in s)
def countdown(n):
while n > 0:
yield n
n -= 1
squares = (x*x for x in s)
| 将Appache网络服务器的log文件中的最后一列的值 相加以计算总共传输了多少字节的数据。 |
要注意的是这个log文件可能会很大,或许好几个Gbytes
每一行的log看起来是这样的:
81.107.39.38 - ... "GET /ply/bookplug.gif HTTP/1.1" 200 2390
字节数显示在最后一列
bytestr = line.rsplit(None, 1)[1]
它要么是一个数字要么是一个值缺失标志(-)
81.107.39.38 - ... "GET /ply/ HTTP/1.1" 304 -
类型转换
if bytestr != '-':
bytes = int(bytestr)
wwwlog = open("access-log")
total = 0
for line in wwwlog:
bytestr = line.rsplit(None, 1)[1]
if bytestr != '-':
total += int(bytestr)
print "Total", total
wwwlog = open("access-log")
bytecolumn = (line.rsplit(None, 1)[1] for line in wwwlog)
bytes = (int(x) for x in bytecolumn if x != '-')
print "Total", sum(bytes)
+--------+ +------------+ +-------+ +-------+
access-log -> | wwwlog | -> | bytecolumn | -> | bytes | -> | sum() | -> total
+--------+ +------------+ +-------+ +-------+
未完待续...
本文是以Open ERP项目开发来介绍bzr工具的使用,文中介绍的方法也适用于其他的软件项目开发。
Open ERP的项目开发使用了 Launchpad 项目管理平台,其代码的版本管理使用的是bzr工具。我们大概已经知道bzr是一个分布式版本控制工具。那么,对于类似Open ERP这样的大型项目,如何才能充分发挥bzr分布式的优势使代码版本历史清晰,协作开发方便呢?本文通过作者对Open ERP的服务器代码管理的实例来介绍一种较好的使用bzr工具的方法。
Continue reading 如何在Open ERP项目开发中使用bzr工具 →我们知道设置SSH SOCKS 代理服务器是很简单的,只要你有一个远端服务器的ssh帐号,使用下面的命令就可以轻易的创建一个套接字代理服务器。
ssh -fND 6666 ssh_user@ssh_server
它的用途是将应用程序的端口请求通过ssh加密通道动态的转发到远端ssh服务器。比如,我们可以设置firefox使用SOCKS5代理服务器并将端口按上面的命令设置为6666, 这样当我们用firefox浏览网页时(也就是对80端口的访问请求)就被转发到远端ssh服务器上作请求了。因为所有的访问请求经过ssh加密通道,所以用来对付墙还是很得心应手的。
因为经常要用bzr版本控制工具同步在launchpad上的项目,但是直截访问launchpad的速度实在太慢了。我发现我在国外租用的ssh服务器访问launchpad的速度非常快,而本地访问ssh服务器的速度也还不错,所以,自然就想到了能不能把bzr通信转发到ssh服务器。很不幸的发现bzr并不支持SOCKS代理服务转发。难不成我们只能忍受bzrlp的龟速,Google一通之后,发现了 tsocks
它的基本原理是:
所有这些是通过设置环境变量 LD—RELOAD``的值为 ``/usr/lib/libtsocks.so 来实现的,tsocks 本身只是一个简单的shell包装(wrapper)脚本,所有的转发任务都是由上述的函数库完成。
安装好tsocks后,编辑文件 /etc/tsocks.conf 将已有的所有内容都注释掉,添加下面两行内容:
server = 127.0.0.1 server_port = 6666 #设置为你的SSH SOCKS服务器开放的端口
就是这么简单,以后我们只要在运行bzr程序前,运行tsocks就可以使用创建好的SSH SOCKS服务器了:
tsocks bzr pull lp:xxxx
这下bzr的访问速度还真是大大的提高了, 其实我们可以用tsocks来实现所有不直接支持SOCKS代理服务的程序。
参考文章:http://www.plenz.com/tunnel-everything
我的笔记本电脑(Thinkpad T61 )的无线连接总是感觉有点古怪,经常会在无线网络中找不到自家的那台贝尔金路由器,但是却能搜出一堆邻居的路由器,而同时家里的其他电脑访问贝尔金路由器又毫无问题。这应该说明贝尔金路由器的工作是正常的,可是在找不到原因的情况下重启几次路由器,Thinkpad T61又突然能找到这台路由器了。最近被它折腾的超烦,路由器重启了N遍,这边的笔记本就是检测不到。忍无可忍,决定彻底的查查原因。试了几次之后发现当我把路由器的频段(Channel)设置从 自动 改为11及以下的设置后,笔记本电脑总能检测到路由器。问题是终于解决了,可是不能使用路由器上的自动频段选择有点不爽,因为路由器的自动频段选择可以避开繁忙的频段而使用周围环境中较少使用的频段,这样无线信号的干扰就会少一点。而且T61无法使用11以上的频段的原因也没有找到。于是戟起google大法,一通搜索之后终于让我的好奇心得到了满足。
我的笔记本上装的是Ubuntu9.10,所以下面的命令都仅适用于Linux。
下面的这个简单的命令实际上一招就能展示我反复试验得出的结论: 就是T61上无法访问11以上的频段,只是不幸的是俺是后来才知道的:
iwlist f
这条命令的结果是显示本机无线可连接的所有频段。在我的电脑上不存在12,13,14这些我的G带宽贝尔金路由器所支持的频段。另外还有一些更高的频段是适用于N带宽路由器的,这里不做讨论。通过搜索了解到,Wifi的IEEE802.11的规范中有regdomain这样的地域规范,就是不同地区所能使用的频段数是不同的。对于G带宽来说美国支持1到11, 欧洲多了12, 13, 而亚洲则另外可以使用14. 所以考虑是不是我的笔记本电脑的无线网卡驱动默认了美国的规范,看能不能改成欧洲或亚洲的。网上介绍了N种办法,因为我的Ubuntu9.10 使用CRDA程序来向内核模块通知domain regulatory的信息(即,地域设置规范),最简单的方法就是:
sudo aptitude install iw
安装iw 无线网管理程序,然后在 /etc/rc.local 中添加一行如下代码,并重启电脑:
iw reg set CN
就是把地域设置为中国。遗憾的是重启电脑后, iwlist f 仍然没有看到久违的12,13,14频段。
lspci
列出了T61使用的是intel 4965 AGN无线模组。再根据该型号来查,原来这个无线模组可能在硬件中设置了美国区,也就是只能使用1到11的频段。至此,我的调查算基本完成,虽然调查并没有为我提供更好的方案,但总算是头绪清爽了,也或许对其他朋友有帮助。另外,对胆大妄为的兄弟可以提供一个进一步的调查方向,就是无线模组的regdomain是纪录在eeprom里的,是可以被擦写修改的,有兄弟饭吃多了,可以往这个方向上再努把力。
最近被电信的DNS劫持搞得烦不胜烦,动不动就被绑架到114search.118114.cn这个恶心的网址上。今天在firefox的addons网站上闲逛还真让我找到了一个很不错的插件来对付这种绑你没商量的强盗行为。
闲话少叙,这个插件的下载位置在:https://addons.mozilla.org/zh-CN/firefox/addon/11787
注:我直接安装插件碰到了一个错误,是因为软件标明的firefox所需版本号有问题,你如果碰到同样的问题可以下载本文所带的附件,解压后拖到firefox里就可以安装了。
安装后,请到firefox的工具-附加组件下找到该插件并点击“首选项“
里面已经设置了对一些网址重定向的处理规则,它们无非就是用正则表达式来过滤需要处理的网址,对114search我们设定如下:
wola, 你不再被流氓们敲闷棍,拉到恶心的地方去了。对于输入错误的网址也会正确显示DNS error 错误信息了。
又案:DNS劫持已不是什么新鲜的东东了,很多ISP为了广告流量都在做这样严重违反互联网规则的事,包括被网友们推崇的openDNS。关于openDNS和GoogleDNS,请参见这篇好文:http://www.chinaz.com/Webmaster/Club/120Q004632009.html
no-redirect插件下载:no-redirect.xpi
| 原文作者: | Brent Burley, Mark Moraes |
|---|---|
| 中文翻译: | Tony (digitalsatori) |
如何才能在Unix终端上显示HTML文本,使其可以表现粗体和下划线。
最简单的方法是编制一个过滤脚本,从标准输入获取HTML然后在标准输出文本和终端控制符。因为本配方针对得唯一对象是Unix, 我们可以通过Unix命令 tput 来获取需要的终端控制符。具体方法是使用Python标准库中os模块中得popen函数来启动tput。
#!/usr/bin/env python
import sys, os, htmllib, formatter
# use Unix tput to get the escape sequences for bold, underline, reset
set_bold = os.popen('tput bold').read( )
set_underline = os.popen('tput smul').read( )
perform_reset = os.popen('tput sgr0').read( )
class TtyFormatter(formatter.AbstractFormatter):
''' a formatter that keeps track of bold and italic font states, and
emits terminal control sequences accordingly.
'''
def _ _init_ _(self, writer):
# first, as usual, initialize the superclass
formatter.AbstractFormatter._ _init_ _(self, writer)
# start with neither bold nor italic, and no saved font state
self.fontState = False, False
self.fontStack = [ ]
def push_font(self, font):
# the `font' tuple has four items, we only track the two flags
# about whether italic and bold are active or not
size, is_italic, is_bold, is_tt = font
self.fontStack.append((is_italic, is_bold))
self._updateFontState( )
def pop_font(self, *args):
# go back to previous font state
try:
self.fontStack.pop( )
except IndexError:
pass
self._updateFontState( )
def updateFontState(self):
# emit appropriate terminal control sequences if the state of
# bold and/or italic(==underline) has just changed
try:
newState = self.fontStack[-1]
except IndexError:
newState = False, False
if self.fontState != newState:
# relevant state change: reset terminal
print perform_reset,
# set underine and/or bold if needed
if newState[0]:
print set_underline,
if newState[1]:
print set_bold,
# remember the two flags as our current font-state
self.fontState = newState
# make writer, formatter and parser objects, connecting them as needed
myWriter = formatter.DumbWriter( )
if sys.stdout.isatty( ):
myFormatter = TtyFormatter(myWriter)
else:
myFormatter = formatter.AbstractFormatter(myWriter)
myParser = htmllib.HTMLParser(myFormatter)
# feed all of standard input to the parser, then terminate operations
myParser.feed(sys.stdin.read( ))
myParser.close( )
Python标准库中的 formatter.AbstractFormatter 基本类可以工作在任何地方。而本配方中的 TtyFormatter 子类則依赖于类Unix的终端。确切的说是依赖于Unix命令 tput , 利用其获取控制符以输出粗体或下划线,并可以重置终端状态。
本配方中的方法要求只要系统中有 tput 命令即可工作,所以本配方可以工作于包括Linux,Mac OS X 在内的大多数类Unix系统。
如果你的终端模拟器支持其他控制输出样式的控制符,你可以对 TtyFormatter 做响应的调整。比如,在Windows系统上,cmd.exe 命令窗口支持标准ANSI控制符。你可以将这些控制符编入要运行的脚本中。
多数情况下,你可能倾向于使用诸如 lynx -dump - 这样的Unix命令,以获得比本配方更加丰富的输出格式。但是如果你正好面对一个没有 lynx 命令的系统,而该系统又恰好安装有Python,那么本配方的方法就很有用了。
Python标准库参考手册和Python in a Nutshell 中关于 formatter 和 htmllib 模块的介绍;使用 man tput 来了解更多关于 tput 的信息。
| 原文作者: | Dale Strickland-Clark, Peter Cogolo, Mark McMahon |
|---|---|
| 中文翻译: | Tony (digitalsatori) |
如何才能使某些字符串在比较或查询时能忽略大小写,而在其它操作时能保持其原来的大小写?
最佳的方案就是把这样需求的字符串封装在一个如下例所示的字符串的子类中:
class iStr(str):
"""
忽略大小写字符串类。
除了在比较和搜索时忽略大小写,其它与str的表现完全一样,
"""
def _ _init_ _(self, *args):
self._lowered = str.lower(self)
def _ _repr_ _(self):
return '%s(%s)' % (type(self)._ _name_ _, str._ _repr_ _(self))
def _ _hash_ _(self):
return hash(self._lowered)
def lower(self):
return self._lowered
def _make_case_insensitive(name):
''' 将str中的一个方法改为忽略大小写后封装到iStr中。'''
str_meth = getattr(str, name)
def x(self, other, *args):
''' 尝试将'other'转为小写。通常情况下others是字符串,
但因为字符串可以跟其他非字符串作比较,
所以可能有无法转为小写的形式而保持其原样。
'''
try: other = other.lower( )
except (TypeError, AttributeError, ValueError): pass
return str_meth(self._lowered, other, *args)
# 对于Python2.4 以后的版本,可以添加以下语句: x.func_name = name
setattr(iStr, name, x)
# 对指定的方法调用 _make_case_insensitive 函数
for name in 'eq lt le gt gt ne cmp contains'.split( ):
_make_case_insensitive('_ _%s_ _' % name)
for name in 'count endswith find index rfind rindex startswith'.split( ):
_make_case_insensitive(name)
# 这里注意我们没有修改的方法有 'replace', 'split', 'strip', ...
# 当然如果你原意,完全可以将他们也添加进来
del _make_case_insensitive # 不再需要这个辅助函数了,删除之
构建这个iStr类值得我们注意的是:首先,因为考虑到字符串的小写版本会在未来的使用中频繁的使用,我们在 __init__ 方法中一次性创建了其小写版本。该小写版本的字符串保存在类的私有属性中,但不是"强制私有"(即,我们使用一个前置下划线而不是两个)。这是因为如果要创建iStr的子类(比如象解决方案方案中提到的那样创建一个子类扩展iStr目前没有涉及的忽略大小写的字符串分割,替换等功能),该子类可能需要访问到其父类的内部信息。iStr中没有提供诸如replace 等的"忽略大小写"版本的方法是因为这样做在一般情况下会让输入输出的关系变得混淆不清。因此,我们鼓励在特别的应用中,通过创建子类来扩展所需的动能。比方说,因为replace 没有被封装在 iStr 中,对iStr的实例调用replace方法,返回的是str实例,而非iStr实例。如果这会给程序带来问题,我们可以将iStr的返回字符串的方法进行封装,确保其返回的是iStr 的实例。为此你需要创建一个类似于"解决方案"中的辅助函数:
def _make_return_iStr(name):
str_meth = getattr(str, name)
def x(*args):
return iStr(str_meth(*args))
setattr(iStr, name, x)
然后你要对所有会返回字符串的相关字符串方法调用以上的辅助函数:
for name in 'center ljust rjust strip lstrip rstrip'.split( ):
_make_return_iStr(name)
字符串中有将近20个此这类方法(包括诸如 __add__, __mul__ 等特殊方法),你还可以对比如 split 和 join 进行类似的封装,但要做一些特殊处理。而对于 encode decode 这样的方法就无法这样封装了,除非我们也设计了忽略大小写的unicode子类。在实际应用中,这些方法都被证实运行正常可靠。通过本例可见Python字符串对象的丰富功能使全局性的自定义工作颇费功夫。
iStr的构筑中我们尽力避免使用繁复的代码(重复而容易出错的代码)来重构字符串中的每个方法。自定义的 metaclass 或者其它的高级技术在本例中也不适用。我们创建了一个辅助函数并以此创建并安装clousre封装函数, 然后通过两个循环来调用该函数,一个循环服务于普通方法,另一个服务于特殊方法。该循环要置于类定义之后,因为它们是用来修改iStr类对象的,必须在创建了类对象之后 才能对其修改。
Python2.4及以上的版本可以为函数对象的 func_name 重新赋值,这样做可以在对 iStr 实施自省操作(比如在互动python解释器中使用help函数)得到一个清晰无误的结果。但是Python2.3将函数对象中的 func_name 属性视为只读,因此在本配方中只是在备注中提到了这种用法,而没有实际的实施以避免对Python2.3不兼容。
在操作中忽略大小写(但是保留原来的大小写形式)的字符串有很多的用途。比如,可以提供更加通融的用户输入,用于诸如windows或Macintosh的忽略大小写的文件系统的的文件名匹配。我们可能需要创建各种各样的"忽略大小写"的容器类,比如字典,列表,集合等等使容器成员或字符串键能忽略大小写。一个比较好的方法是一次性定义好"忽略大小写"的比较和搜索功能。在创建"忽略大小写容器类"时,或改变容器成员时,我们可以利用本配方中的 iStr 将其中的 str 转变为 iStr 实例。
比如,对于一个其成员都为字符串的列表,希望能按照忽略大小写的方式来处理(比如在使用 sort count index 等方法时):
class iList(list):
def _ _init_ _(self, *args):
list._ _init_ _(self, *args)
# rely on _ _setitem_ _ to wrap each item into iStr...
self[:] = self
wrap_each_item = iStr
def _ _setitem_ _(self, i, v):
if isinstance(i, slice): v = map(self.wrap_each_item, v)
else: v = self.wrap_each_item(v)
list._ _setitem_ _(self, i, v)
def append(self, item):
list.append(self, self.wrap_each_item(item))
def extend(self, seq):
list.extend(self, map(self.wrap_each_item, seq))
如果你希望在特定的程序中对上例使用自定义的 iStr 的子类,只需要继承 iList 并覆写一个类成员 wrapped_each_item
Python库参考手册和Python in a Nutshell 中关于 str, 字符串方法的章节,以及关于用于比较和hashing的特殊方法的说明。
| 原文作者: | David Goodger, Peter Cogolo |
|---|---|
| 中文翻译: | Tony (digitalsatori) |
要将Uicode文本输出到HTML或是XML应用程序,且只能用较为流行但受限的编码比如:ASCII码,或Latin-1,如何操作?
Python 有一个叫 xmlcharrefreplace 的编码出错处理器,它可以将选定编码之外的字符替换为XML数字字符参考(XML numeric characters references):
def encode_for_xml(unicode_data, encoding='ascii'):
return unicode_data.encode(encoding, 'xmlcharrefreplace')
上述的方法也可以用来处理HTML输出,但是我们希望能用HTML的‘符号实体‘(symbolic entity)。这样的话,我们就要自己定义一个函数并将其注册为编码错误处理函数。弄这么个函数其实并不难,因为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_ _':
# demo
data = u'''\
<html>
<head>
</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)
运行这个文件,可以看到如下结果:
<li>à (a + grave) <li>ç (c + cedilla) <li>é (e + acute) ... <li>£ (British pound) <li>€ (Euro) <li>∞ (infinity) ... <li>à (a + grave) <li>ç (c + cedilla) <li>é (e + acute) ... <li>£ (British pound) <li>€ (Euro) <li>∞ (infinity)
encode_for_xml 比较通用, encode_for_html 产生的结果的可读性较强。两个函数产生的结果放到浏览器里看是完全一样的。你可以运行以上这个Python文件并将结果重定向到一个html文件,然后用浏览器打开查看。
必须要记得Unicode数据在打印或写入文件前一定要做编码处理。UTF-8是一个不错的字符编码,因为他能处理所有的Unicode字符。但是目前还有很多用户和程序在使用ASCII码或Latin-1。如果Unicode数据中有超出指定编码范围的字符(比如本例中的带重音的字符和所有的符号都无法用ASCII编码,而无限符号(infinity)无法用Latin-1编码),指定的编码无法自己处理这些数据。Python提供了一个称为 xmlcharrefreplace 错误处理函数,它可以将无法编码的字符用XML数字字符参考来替代,比如: ∞ 表示无限符号。在本配方中展示了如何来编写和注册另一个近似的错误处理函数 html_replace ,这个函数主要用于处理HTML输出。 html_replace 将无法编码的字符用更加可读的HTML符号实体来替代,比如用 ∞ 来表示无限符号。 html_replace 不是很通用,因为它并不能处理所有的Unicode字符,而且也不能用于非HTML的应用环境。
上述的错误处理函数对于除XML或HTML以外的输出是没有意义的。比如TeX或其它标记语言并不能识别XML数字字符参考。当然,如果你知道如何为这些标记语言创建相应的符号参考,你就可以用本配方中的方法来创建和注册相应的错误处理函数。
另外,Python标准库中的 codecs 模块提供了一个有效的方法,将Unicode数据编码输出到文件,并根据设定进行错误处理:
outfile = codecs.open('out.html', mode='w', encoding='ascii',
errors='html_replace')
现在我们可以用 outfile.write(unicode_data) 将任意Unicode字符串 unicode_data 输出到指定的文件,编码和错误处理会自动进行。当输出结束后,我们需要调用 outfile.close() 。
Python库参考手册和Python in a Nutshelll中关于 codecs 模块和 htmlentitydefs 的介绍
| 原文作者: | David Ascher |
|---|---|
| 中文翻译: | Tony (digitalsatori) |
需要将Unicode字符打印到标准输出(比如在Debug时),但是它们不能使用默认的编码,怎么办?
使用Python标准库中的 codecs 模块作为编码转换器来封装 sys.stdout (标准输出流)。比如我们的输出是到一个使用ISO-8859-1编码的终端,可以这样来写代码:
import codecs, sys
sys.stdout = codecs.lookup('iso8859-1')[-1](sys.stdout)
Unicode字符串处在一个足以容纳全世界所有语言所包含的字符的空间中。幸运的是,作为Unicode的使用者,我们不必了解Unicode字符串的内部表现方式。但是对于象 sys.stdout 这样的文件流,只能处理与特定编码关联的字节。我们可以改变Python的 site 模块来改变文件所使用的默认编码,但是这样的改变会全局影响Python ,使其它使用Python安装时的默认编码的程序出现混乱。(Python的默认标准编码是ASCII)。因此,我们不推荐这类改动。
本配方采用了一个更好的方法:将 sys.stdout 重新绑定到一个接收Unicode输入,以ISO-8859-1(也称为"Latin-1")编码输出的文件流。该方法并不会改变之前的 sys.stdout 的编码。首先我们保存当前的以ASCII为编码的 sys.stdout:
>>> old = sys.stdout
然后,我们创建一个无法通过 sys.stdout 直接输出的Unicode字符串:
>>> char = u"\N{LATIN SMALL LETTER A WITH DIAERESIS}"
>>> print char
Traceback (most recent call last):
File "<stdin>", line 1, in ?
UnicodeError: ASCII encoding error: ordinal not in range(128)
如果在做以上操作时没有出现错误,那是因为Python认为它知道你的终端所使用的编码(比如你的终端是Python自带的开发环境IDLE, 多数情况下Python会使用正确的编码)。但是如果确实有错误信息出现,或者没有出现错误信息,但是输出并不是期待中的输出,因为Python并不知道你的终端使用的是比如UTF-8这种编码。我们可以将 sys.stdout 用以UTF-8编码的 codecs 输出流封装,并将 sys.stdout 重新绑定到这个封装的输出流:
>>> sys.stdout = codecs.lookup('utf-8')[-1](sys.stdout)
>>> print char
ä
以上方法工作的前提是,运行Python互动解释器的终端,终端模拟器,或其它窗口支持UTF-8编码,并且拥有需要显示的字符的字体。如果你没有符合这样要求的程序或设备,请在互联网上下载适用于你所使用平台的程序。
在Python库参考手册和Python in a Nutshell中关于 codecs 和 site 模块,以及 sys 模块中的 setdefaultencoding 函数; Python食谱1.20 Python食谱1.21