2007年06月15日

需求:

Python可以使用string来保存字符串或任意字节

.我们需要判断字符串中的是文本,还是字节流,目前还没有什么明确的算法来区分两种情况.

讨论:

我们需要自己设计出算法来区分字节流和字符串,比如判断是否有超过30%的字节都包含着空字符,控制字符或者非ascii字符(字节高位设置为1),我们必须要自己处理,也要为不同的场景设计出不同的算法:

from _ _future_ _ import division # ensure / does NOT truncate
import string
text_characters = "".join(map(chr, range(32, 127))) + "\n\r\t\b"
_null_trans = string.maketrans("", "")
def istext(s, text_characters=text_characters, threshold=0.30):
    # if s contains any null, it’s not text:
    if "\0" in s:
        return False
    # an "empty" string is "text" (arbitrary but reasonable choice):
    if not s:
        return True
    # Get the substring of s made up of non-text characters
    t = s.translate(_null_trans, text_characters)
    # s is ‘text’ if less than 30% of its characters are non-text ones:
    return len(t)/len(s) <= threshold

可以通过设置istext的threshold参数来定制算法,也可以通过修改text_characters参数来改变字符集.比如,如果需要判断ISO-8859-1编码的意大利重音字符,就需要添加重音符号给text_characters,如" àèéìÃ2Ã1"

上面的代码中需要注意的是,/做整数除法,不会截断小数点,如果要取整除法,请使用//. 默认情况下,如果除数和被除数都是整数,那么结果也是整数.

例如:

>>>5 / 3
1
>>>5 // 3
1
>>>5.0 / 3
1.6666666666666667
>>>5.0 // 3
1.0

所以在例子的第一行我们写了:

from _ _future_ _ import division

这保证在我们的代码中,被除数和除数都是整数时,它们的结果依然可以是小数.

相关说明:

from __future__ import division 请放在代码的 第一句,我自己安装SOAPpy库时,就因为这个问题不能正常安装,修改代码后安装成功了.

需求:

给定一个字符集合,需要构造一个过滤函数,使对于任意字符串s

,改方法都能将其,使只包含集合内的字符.

讨论:

string的Translate方法是处理这一类问题的最快方法.然而,要想用translate解决需求提出的问题,我们需要做一些前期工作.translate的第一个参数是一个字符转换表.我们在这里并不需要转换字符 ,所以我们要让第一个参数表示不做任何转换.第二个参数是指要删除的字符串,因为我们的需求不是要删除字符,而是要保留字符,所以我们要构造出我们不需要的字符的集合.对于这样的要求,使用内函数是比较方便的,如在上一节,我们也实现了类似的需求.

import string
# 构造一个字符转换表,表示不做任何转换.
allchars = string.maketrans(”, ”)
def makefilter(keep):
# 构造出我们不需要的字符集合
     delchars = allchars.translate(allchars, keep)
# 定义内函数,返回我们需要的过滤器.
     def thefilter(s):
         return s.translate(allchars, delchars)
     return thefilter
if _ _name_ _ == ‘_ _main_ _’:
just_vowels = makefilter(’aeiouy’)
print just_vowels(’four score and seven years ago’)
# 输出: ouoeaeeyeaao
print just_vowels(’tiger, tiger burning bright’)
# 输出: ieieuii

理解这 一节的关键是理解string的maketrans和translate的实现机制.translate返回了一个字符串s的副本,在副本中,处于第一个参数(转换表)中的字符被替换了,而处于第二个参数中的字符被删除了.maketrans方法是用来构造字符转换表的.所谓字符转换表t是一个包含256个字符的字符串: 当你把t做为translate的第一个参数时,s中的每一个字符c都被转换为t[ord(c)].
在这一节中,我们首先分写了问题,将它划分为与处理和执行两个部分
,这样不但减少了问题的复杂度,也提高了执行的效率.allchars是可重用的,可以被所有的过滤函数共享.而translate的第二个参数delete,我们使用了方法工厂来构造,也使用translate来达到最高的效率.

如果把allchars做为makefilter的参数,这样的过滤器能返回排序好的字符串,而且删除了重复字符.
可以这样来定义:

def canonicform(s):
    return makefilter(s)(allchars)

其中return那一句,s做为makefilter的参数,而allchars做为thefilter的参数.
也可以使用lambda函数写法来定义内函数:

return lambda s: s.translate(allchars, delchars)

当然,使用def来定义使得代码更清晰,易读.

对于这个需求,我们也会想到用set来处理,然而,使用translate处理字符串是最高效的.当然其局限性也显而易见,它只能处理ascii常规字符,不能处理unicode.

为了使得unicode字符串也能满足我们的需求,还要做一些与处理工作,unicode的translate方法只有一个参数:一个map或者一个序列,它包含了字符串中字符的序列,表中不包含的字符,就直接复制到结果中去,对于要删除的字符,在map中对应的值是None.

一般来说,我们使用dict或list做为unicode字符串translate方法的参数.但对于这一节的需求(保留一些字符,删除其余的),我们要初始化一个巨大的map,然后把它们的值都映射为None.相反,我们构造一个简单的类,让它实现__getitem__方法.__getitem__方法是让外界可以通过[]来索引序列元素的方法,可以理解为重载了[].同时,对于简单类,我们可以使用别名来使用它.为了使类可以直接执行,我们让它实现恶劣__call__方法.

import sets
class Keeper(object):
    def _ _init_ _(self, keep):
        self.keep = sets.Set(map(ord, keep))
    def _ _getitem_ _(self, n):
        if n not in self.keep:
            return None
        return unichr(n)
    def _ _call_ _(self, s):
        return unicode(s).translate(self)
makefilter = Keeper
if _ _name_ _ == ‘_ _main_ _’:
    just_vowels = makefilter(’aeiouy’)
    print just_vowels(u’four score and seven years ago’)
# 输出: ouoeaeeyeaao
    print just_vowels(u’tiger, tiger burning bright’)
# 删除: ieieuii

相关说明:

translate(…)
    S.translate(table) -> unicode
   
    Return a copy of the string S, where all characters have been mapped
    through the given translation table, which must be a mapping of
    Unicode ordinals to Unicode ordinals, Unicode strings or None.
    Unmapped characters are left untouched. Characters mapped to None
    are deleted.

2007年06月14日

需求:

想使用强大的string的translate方法,却困惑于它复杂的用法和参数,也不知道string.maketrans的工作机制

.我们需要的只是简单的使用它们的功能.

讨论:

我们在这里简单实现一个方法工厂,可以处理常用的这一类的问题:

import string
def translator(frm='', to='', delete='', keep=None):
if len(to) == 1:
to = to * len(frm)
trans = string.maketrans(frm, to)
if keep is not None:
allchars = string.maketrans('', '')
delete = allchars.translate(allchars, keep.translate(allchars, delete))
def translate(s):
return s.translate(trans, delete)
return translate 下面是一些translator的用法: 可以只保留需要的字符 >>> digits_only = translator(keep=string.digits)
>>> digits_only('Chris Perkins : 224-7992')
'2247992' 可以过滤指定的字符:

>>> no_digits = translator(delete=string.digits)
>>> no_digits(’Chris Perkins : 224-7992′)
‘Chris Perkins : -’

可以替换指定的字符:

>>> digits_to_hash = translator(from=string.digits, to=’#')
>>> digits_to_hash(’Chris Perkins : 224-7992′)
‘Chris Perkins : ###-####’

相关说明:

内部方法,在上面的例子中,我们使用了一个内部方法来实现方法工厂,返回一个变量来表示内部方法,然后接收参数来实现功能.
最简单的方法工厂可以写成下面这个样子:
def make_adder(basenum):
    def adder(args):
        return args+basenum
    return adder

比如我们要做一个以100为基数的加法器,可以这样使用:

base100 = make_addr(100)
print base100(45)
>>>145

讨论中的例子,我们返回了自己定制的translate方法 ,它以我们自己定制的delete为参数,来实现我们的keep需求:

allchars = string.maketrans('', '')

返回了包含所有字符的列表

keep.translate(allchars, delete)

返回了过滤掉删除字符的字符表.

allchars.translate(allchars, keep.translate(allchars, delete))

又做了一次运算,现在剩下的只是要删除的字符了.

如果keep和delete不同时使用,可以这样写:

allchars = string.maketrans('', '')
delete = allchars.translate(allchars, keep)

maketrans(…)
    maketrans(frm, to) -> string
   
    Return a translation table (a string of 256 bytes long)
    suitable for use in string.translate.  The strings frm and to
    must be of the same length.

translate(…)
    S.translate(table [,deletechars]) -> string
   
    Return a copy of the string S, where all characters occurring
    in the optional argument deletechars are removed, and the
    remaining characters have been mapped through the given
    translation table, which must be a string of length 256.

需求:

给定一个字符集合,需要判断在特定字符串内,是否包含该集合的字符

.

讨论:

最简单,直观,效率最高的算法就是使用循环迭代.而且还具有通用性,不仅适用与字符串,也适用与其它序列.

 def containsAny(seq, aset):
""" Check whether sequence seq contains ANY of the items in aset. """
for c in seq:
if c in aset: return True
return False 当然,也可以使用更高级的办法,用Python提供的迭代工具: import itertools
def containsAny(seq, aset):
for item in itertools.ifilter(aset._ _contains_ _, seq):
return True
return False 另:对于和集合相关的问题,都可以使用集合来解决.对于我们需求,可以使用下面的方式来实现: def containsAny(seq, aset):
return bool(set(aset).intersection(seq)) 这个方法返回了两个集合的交集,也就是说,两个集合中所有的元素都
进行了判断,从效率上讲,没有上面提供的两种方法好.然而,如果需求是需要判断集合内的字符是否都包含在字符串内,使用集合提供的方法会更方便一些: def containsAll(seq, aset):
""" Check whether sequence seq contains ALL the items in aset. """
return not set(aset).difference(seq) 如果需求是判读字符串内是否只包含集合内的字符,可以用下面的算法
: def containsOnly(seq, aset):
""" Check whether sequence seq contains ONLY items in aset. """
for c in seq:
if c not in aset: return False
return True

相关说明:

intersection(…)
    Return the intersection of two sets as a new set.
   
    (i.e. all elements that are in both sets.)

difference(…)
    Return the difference of two sets as a new set.
   
    (i.e. all elements that are in this set but not the other.)

需求:

反转字符串中的单词或字符.

讨论:

如果是别的语言,通常的做法是写一个循环,然后利用临时变量,构造反转后的字符串.对于字符的反转,在Python中有一个非常简便的方法,利用切片功能.

newstring = astring[::-1]

这样,就能获得astring的反转字符串了.
对于单词的反转,可以利用序列的reverse方法:

words = astring.split()
words.reverse()
newstring = ‘ ‘.join(wrods)

这里我们假设单词之间是用空白字符分隔的.空白字符包括空格,回车,TAB等.
用一个语句表示的方法:

newstring = ‘ ‘.join(astring.split()[::-1])

这里我们用到了上面说的第一种方法.
看了上面两个方法,需要注意的时,string没有reverse方法.可能因为有了[::-1]已经满足了需求了吧.

如果单词间的分隔符不是空白字符,可以使用正则式来实现需求,如:

import re
newstring = re.split(r’(\s+)’, astring)         # 用’()’分隔
newstring.reverse( )
newstring = ”.join(newstring)  

或者更简单的写法:

newstring = ”.join(re.split(r’(\s+)’, astring)[::-1])

当然,如果这样写,就不符合Python的简单清晰的原则了.

相关说明:

split(…)
    S.split([sep [,maxsplit]]) -> list of strings
    
    Return a list of the words in the string S, using sep as the
    delimiter string.  If maxsplit is given, at most maxsplit
    splits are done. If sep is not specified or is None, any
    whitespace string is a separator.

join(…)
    S.join(sequence) -> string
    
    Return a string which is the concatenation of the strings in the
    sequence.  The separator between elements is S.

reverse(…)
    L.reverse() — reverse *IN PLACE*

关于正则式的说明请看后续的章节.

需求:

要将一些字符串拼接成一个字符串.

讨论:

最容易想到的方法是使用’+':

newstring = str1 + ‘ ‘ + str2 + ‘ ‘ + str3 + ‘!’

然而在Python中,不推荐使用上面的做法,这可能造成代码的效

率底下.
string对象是不可改变的字符序列,一个’+'操作
,要先构造一个新的string对象,然后再做字符串的拼接,而不是直接改变原有的字符串.当一个操作完成后,临时使用的对象又被释放掉了.也就是说,如果有N字符串要拼在一起,使用’+'操作的话,就要生成N-1次临时string对象,做N-1次拼接运算,然后再释放这N-1个临时对象.这样的效率是可想而知的 .
根据上面的说明,推荐使用Python的内建方法:join.

newstring = ‘ ‘.join([str1,str2,str3,'!'])

类似的,可以使用另外一种方法来实现我们的需求.
在Python中,可以使用字符串格式化符号:%
.像C的printf一样的使用方法:

newstring =  ‘%s %s %s!’ %(str1,str2,str3)

这个方法不但适用字符串的拼接,也适合与多种类型构成字符串,如:

newstring = ‘%d + %d = %d %s’ %(1,2,3,’done’)

两种方法各有各的优点:join适用于要拼接的字符串个数不定 ,且连接字符确定的情况;而%适用于

相关说明:

join(…)
    S.join(sequence) -> string
    
    Return a string which is the concatenation of the strings in the
    sequence.  The separator between elements is S.

2007年06月13日

#~ 中文字符乱码正确显示
#linux下面使用:code.page=65001
if PLAT_WIN
    code.page=936
    output.code.page=936
if PLAT_GTK
    code.page=65001
    output.code.page=65001
#~ Big5:code.page=950
#~ 最大化
position.width=-1
position.height=-1
#~ 滚动条
end.at.last.line=0
#~ 工具条
#~ toolbar.visible=1
#~ 状态栏
statusbar.visible=1
#~ 自动补全xml结束标签
xml.auto.close.tags=1
#~ 记录最近打开的文件
save.recent=1
#~ 显示行号
line.margin.visible=1
#~ 设置状态栏
statusbar.text.1= [ 行: $(LineNumber) , 列: $(ColumnNumber) ,共:$(NbOfLines) ] ($(OverType)) | ($(EOLMode))
#~ 当前行
caret.line.back=#E8F2FE
#~ 文档背景,保护眼睛
style.*.32=$(font.base),back:#CCE8CF
#~ 行号字符宽度
line.margin.width=3+
#~ 一个文档时隐藏tab栏
tabbar.hide.one=1
#~ 多行tab栏模式
tabbar.multiline=1

#~ 当前文件被外部修改时自动重新载入
load.on.activate=1
#~ 当load.on.activate=1时,且本条设1,重新载入时会先询问你
are.you.sure.on.reload=1
#~ 只有一个scite实例
check.if.already.open=1
#~ 自动补全
autocompleteword.automatic=1
#~ 调整编辑区和输出区的大小
magnification=1
output.magnification=1
#~ 输出栏在下面
split.vertical=0
#~ 执行命令前清空输出区的内容
clear.before.execute=1
#~ 缓冲区个数
buffers=18
#~ 字体大小
font.base=font:Verdana,size:9

#~启用折叠
fold=1
#~编辑区折叠列初始化宽度.
fold.margin.width=16
#~折叠符号,0为三角形,1为展开-收缩+, 2为圆形,3方形。一般选2
fold.symbols=2
#~初始化是否折叠。一般设成1,这样再长的文章

,因为只显示结构,看上去了一目了然。
#~ fold.on.open=1
#~设成1,伸展时折叠符号区有一条短线指示折叠位置
。收缩时显示一条长线。
fold.compact=1
#~xml和html文件折叠
fold.html=1

#~标题栏显示信息,0为文件名,1为全路径,2为显示文件名和目录名。
title.full.path=1
#~一个tab占几个空格,一般设成4。
tabsize=4
#~一个自动缩进占几个空格,一般为4
indent.size=4
#~1为初始化时自动换行
wrap=0

#~设置中文自动提示用
chars.cn=的一是了不在有人上这大我国来们和个他中说到地为以子小就时全可下
要十生会也出年得你主用那道学工多去发作自好过动对行里能二天三同成活太事面民日家方后都于之分经种还看产所起把进前着没而样部长又问法从本定见两新现如么力等电开五心只实社水外政很高月业当义些加老着四头因向理点合明无机意使第正度物想体此知关制然其表重化应各但者间百比什儿公做九相气命西话将内与由利今手平量员回情几最八级位结性代教次路党六便原军总走象口七先常题入给己队战果完反白建革立少文打论门东女放期真数展资通农名解叫提或山线条别万系已变形它边阶报官决她及争声北求世耍美再听才运必安取被南接华干区身济共计特改吃书马组界议车并海育思设件光强品直许造务流治领联金记任受极

基质指帮目市快千导花科难深保住统管处认志图则研劳每场带亲至根更斗收信究且怎近非料何呢热术夫眼交布石达步拉众省风据奸增程火团字却油米委色式切望器办群观算调母土较请元爱持清广张连压觉识林际举即死专局类空单权毛师商孩装批府找往王校该未席约照易神克号京转须半习青早规验拿服节精树传备钱技讲告德参斯具织集病友谈示积亚复厂越支婚历兵胜选整铁势笑院板球河吗除准况影倒若格断甚速言采哪离县写台古远
#~ 缩进可见
view.indentation.whitespace=1

#~长行指示
edge.column=200
edge.mode=1
edge.colour=#F9F9F9

#~设置错误行的前景色和背景色
error.marker.fore=#0000A0
error.marker.back=#DADAFF
#~ 定义菜单
user.context.menu=\
||\
UTF-8|IDM_ENCODING_UCOOKIE|\
CodePage|IDM_ENCODING_DEFAULT|

#~ 定义api文件
if PLAT_WIN
    api.$(file.patterns.java)=$(SciteDefaultHome)\api
\java150.api
    api.$(file.patterns.cs)=$(SciteDefaultHome)\api\cs
.api
    api.$(file.patterns.cpp)=$(SciteDefaultHome)\api\cpp
.api
    api.$(file.patterns.py)=$(SciteDefaultHome)\api
\python.api
    api.$(file.patterns.php)=$(SciteDefaultHome)\api\php
.api
if PLAT_GTK
    api.$(file.patterns.java)=$(SciteDefaultHome)/api
/java150.api
    api.$(file.patterns.cs)=$(SciteDefaultHome)/api/cs
.api
    api.$(file.patterns.cpp)=$(SciteDefaultHome)/api/cpp
.api
    api.$( file.patterns.py)=$(SciteDefaultHome)/api
/python.api
    api.$(file.patterns.php)=$(SciteDefaultHome)/api/php
.api
#~ 定义缩写文件
if PLAT_WIN
    abbreviations.*.cpp=$(SciteDef
aultHome)\abbrev\cppAbbrev.properties
    abbreviations.*.cs=$(SciteDefa
ultHome)\abbrev\csAbbrev.properties
    abbreviations.*.java=$
(SciteDefaultHome)\abbrev\javaAbbrev.properties
if PLAT_GTK
    abbreviations.*.cpp=$(SciteDef
aultHome)/abbrev/cppAbbrev.properties
    abbreviations.*.cs=$(SciteDefa
ultHome)/abbrev/csAbbrev.properties
    abbreviations.*.java=$
(SciteDefaultHome)/abbrev/javaAbbrev.properties

需求:

需要过滤掉输入字符串的前导,后续空格或其它字符.这在处理用户输入的时候比较有用.

讨论:

和其它语言类似,Python也提供了lstrip,rstrip和strip方法,类似Delphi和C#的trim方法.
用法:

>>> x = ‘    test   ‘
>>> print ‘|’, x.lstrip( ), ‘|’, x.rstrip( ), ‘|’, x.strip( ), ‘|’
| test    |     test | test |

另外,这三个方法还可以接受一个参数,用于过滤指定的字符组成的串 ,如:

>>> x = ‘xyxxyy testyx  yyx’
>>> print ‘|’+x.strip(’xy’)+’|’
| testyx  |

需要注意的是:testyx前面有一个空格,因为空格前的所有的x,y都被过滤掉了,而test后面的yx没有被过滤掉,是因为执行到testyx后面那个空格的时候就完成了.如果我们只需要留下’test’,输入下面的语句即可:

>>> print x.strip(’xy ‘)
test

相关说明:

lstrip(…)
    S.lstrip([chars]) -> string or unicode
   
    Return a copy of the string S with leading whitespace removed.
    If chars is given and not None, remove characters in chars instead.
    If chars is unicode, S will be converted to unicode before stripping

rstrip(…)
    S.rstrip([chars]) -> string or unicode
   
    Return a copy of the string S with trailing whitespace removed.
    If chars is given and not None, remove characters in chars instead.
    If chars is unicode, S will be converted to unicode before stripping

strip(…)
    S.strip([chars]) -> string or unicode
   
    Return a copy of the string S with leading and trailing
    whitespace removed.
    If chars is given and not None, remove characters in chars instead.
    If chars is unicode, S will be converted to unicode before stripping

2007年06月12日

需求:

想要让输出的字符能够按照左对齐,右对齐,居中对齐的格式排列.这对于生成格式化的文本很重要.
让人回想起在C语言中的printf("%nd")的格式
,其中n如果是-的,就是右对齐,不过好像没有居中对齐的概念啊.

讨论:

在Python中,是用str的rjust,ljust,center方法来实现上述的功能.看下面的例子:

>>> print ‘|’,'Hello’.ljust(15),’|',‘Hello’.rjust(15),’|',’Hello’.center(15),’|’
| Hello           |           Hello |      Hello      |

挺酷的,是吧,第一次用这个功能的时候,心里有说不出的方便的感觉 ,呵呵.

相关说明:

ljust(…)
    S.ljust(width[, fillchar]) -> string
   
    Return S left justified in a string of length width. Padding is
    done using the specified fill character (default is a space).

rjust(…)
    S.rjust(width[, fillchar]) -> string
   
    Return S right justified in a string of length width. Padding is
    done using the specified fill character (default is a space)

center(…)
    S.center(width[, fillchar]) -> string
   
    Return S centered in a string of length width. Padding is
    done using the specified fill character (default is a space)

需求:

需要判断一个对象,或者方法的一个参数,看它们是否是字符串.

讨论:

判断一个对象是否是字符串或者unicode串的最简单有效的办法是使用isinstance和basestring

def isString(str):
    return isinstance(str, basestring)

一般的说,判断一个对象是否是字符串,最容易想到的方法是:

def isString(str):
    return type(str) is type(”)

这样有一些缺点:无法判断unicode字符串,或者用户从basestring继承下来的字符串类型.

当然,上面的算法在有些情况下也会失效:如Python类库中的UserString
那样,可以使用下面的算法:

def isStringLike(str):
    try: str + ”
    except: return False
    else: return True

这样的算法会降低方法的效率,但能适应更多的情况.

相关说明:

class basestring(object)
 |  Type basestring cannot be instantiated; it is the base for str and unicode.
 | 
 |  Data and other attributes defined here:
 | 
 |  __new__ = <built-in method __new__ of type object at 0×8147420>
 |      T.__new__(S, …) -> a new object with type S, a subtype of T

isinstance(…)
    isinstance(object, class-or-type-or-tuple) -> bool
   
    Return whether an object is an instance of a class or of a subclass thereof.
    With a type as second argument, return whether that is the object’s type.
    The form using a tuple, isinstance(x, (A, B, …)), is a shortcut for
    isinstance(x, A) or isinstance(x, B) or … (etc.).

class type(object)
 |  type(object) -> the object’s type
 |  type(name, bases, dict) -> a new type