2007-06-15

 

Python Cook 1.10 从字符串中过滤非指定集合的字符

需求:

给定一个字符集合,需要构造一个过滤函数,使对于任意字符串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.


标签:


Comments: 发表评论



<< Home

This page is powered by Blogger. Isn't yours?