《Python Cookbook(第2版)中文版》——1.10 过滤字符串中不属于指定集合的字符

简介:

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

1.10 过滤字符串中不属于指定集合的字符

任务

给定一个需要保留的字符的集合,构建一个过滤函数,并可将其应用于任何字符串s,函数返回一个s的拷贝,该拷贝只包含指定字符集合中的元素。

解决方案

对于此类问题,string对象的translate方法是又快又好用的工具。不过,为了有效地使用translate来解决问题,事先我们必须做一些准备工作。传递给translate的第一个参数是一个翻译表:在本节中,我们其实不需要什么翻译,所以我们必须准备一个特制的参数来指明“无须翻译”。第二个参数指出了我们需要删除的字符:这个任务要求我们保留(正好反过来,不是删除)属于某字符集合的字符,所以我们必须为该字符集合准备一个补集,作为第二个参数—这样就可以删除所有我们不想保留的字符。闭包是一次性完成所有准备工作的最好方法,它能够返回一个满足需求的快速过滤函数:

import string
# 生成所有字符的可复用的字符串,它还可以作为
# 一个翻译表,指明“无须翻译”
allchars = string.maketrans('', '')
def makefilter(keep):
     """ 返回一个函数,此返回函数接受一个字符串为参数
         并返回字符串的一个部分拷贝,此拷贝只包含在
         keep中的字符,注意keep必须是一个普通字符串
     """
     # 生成一个由所有不在keep中的字符组成的字符串: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

讨论

理解本节技巧的关键在于对Python标准库的string模块的maketrans函数以及字符串对象的translate方法的理解。translate应用于一个字符串并返回该字符串的一个拷贝,这个拷贝中的所有字符都将按照传入的第一个参数(翻译表)指定的替换方式来替换,而且,第二个参数指定的所有字符都将被删除。maketrans是创建翻译表的一个工具函数。(翻译表是一个正好有256个字符的字符串t:当你把t作为第一个参数传递给translate方法时,原字符串中的每一个字符c,在处理之后都被翻译成了字符t[ord(c)]。)

在本节的技巧中,我们将整个过滤任务分解为准备阶段和执行阶段,使效能达到了最大化。由于包含所有字符的字符串需要重复使用,我们只创建它一次,并在模块导入后将它设置为全局变量。采用这种方式的原因是我们确定每个过滤函数都使用同样的翻译表,因此它非常节省内存。而我们要传递给translate的第二个参数—需要删除的字符,则依赖于需要保留的字符集合,因为它完全是后者的“补集”:我们需要通知translate删除我们不想保留的字符。所以,我们用makefilter工厂函数来创建需要删除的字符集合(字符串),即通过使用translate方法来删除“需要保留的字符”,这一步很快得以完成。和本节的其他函数一样,无论是创建还是执行,translate的速度都非常快。程序中的执行部分给出的测试代码,则展示了如何通过调用makefilter构建一个过滤函数,并给这个过滤函数绑定一个名字(只需简单地给makefilter的返回结果指定个名字即可),然后对一些测试字符串调用该函数并打印出结果。

顺带一提,用allchars作为参数调用过滤函数会把所有需要保留的字符处理成一种非常规整的字符串—严格按照字母表排序而且没有重复的字符。可以根据这种思路编写一个很简单的函数,将以字符串形式给出的字符集合处理成规整的形式:

def canonicform(s):
     """ 给定字符串s,将s的字符以一种规整的字符串形式返回:
         按照字母顺序排列且没有重复 """
     return makefilter(s)(allchars)

在“解决方案”小节中给出的代码,使用了def语句来建立一个嵌套的函数(闭包),这是因为def是最常见、最通用,也是最清晰的创建函数的语句。不过如果你乐意,也可以用lambda来代替原来的语句,只需修改makefilter函数中的def和return语句,然后写成只需一行的return lambda语句:

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

大多数Python玩家认为,相对于lambda,def更清晰且更具可读性。

既然本节处理的一些字符串可以被看作字符集合,也可以用sets.Set类型(或Python 2.4中的内建set类型)来完成相同的任务。但得益于translate方法的威力和速度,在类似的这种直接处理字符串的任务中,使用translate总是比通过set来实现要快一些。不过,正如第1.8节提到的,本节中给出的技巧只适用于普通字符串,对Unicode字符串则不适用。

为了能够解决Unicode字符串的问题,我们需要做完全不同的准备工作。Unicode字符串的translate方法只需要一个参数:一个序列或者映射,并且根据字符串中的每个字符的码值进行索引。码值不是映射的键(或者序列的索引值)的字符会被直接复制,不做改变。与每个字符码对应的值必须是一个Unicode字符串(该字符的替换物)或者None(这意味着该字符需要被删除)。这种用法看上去既优雅又强大,可惜对于普通字符串却不适用,所以我们还得重写代码。

通常,我们使用dict或list作为Unicode字符串的translate方法的参数,来翻译或者删除某些字符。但由于本节任务有些特殊(保留一些字符,删掉所有其余字符),我们可能会需要一个非常庞大的dict或string—但仅仅是把所有的其他字符映射到None。更好的办法是,编写一个简单的大致实现了 _getitem _(进行索引操作时会调用的特殊方法)方法的类。一旦我们花点功夫完成了这个小类,我们可以让这个类的实例可被调用,还可以直接给这个类起个makefilter的别名:

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

我们也可以直接就把这个类命名为makefilter,但是,基于传统,一个类的名字通常应该首字母大写;遵循传统一般来说没有什么害处,所以,代码就成了这个样子。

相关文章
|
11天前
|
Python
1167: 分离字符串(PYTHON)
1167: 分离字符串(PYTHON)
|
2天前
|
程序员 索引 Python
06-python数据容器-set(集合)入门基础操作
06-python数据容器-set(集合)入门基础操作
|
4天前
|
数据采集 Python
python学习9-字符串
python学习9-字符串
|
4天前
|
Python
python学习8-集合
python学习8-集合
|
11天前
|
Python
171: 字符串的倒序(python)
171: 字符串的倒序(python)
|
28天前
|
Python
掌握Python中的集合推导式
掌握Python中的集合推导式
|
28天前
|
Python
探索Python集合推导式的进阶应用
探索Python集合推导式的进阶应用
|
28天前
|
存储 数据处理 Python
深入剖析Python集合推导式的独特之处
深入剖析Python集合推导式的独特之处
|
28天前
|
数据处理 Python
Python集合推导式的优雅与实用
Python集合推导式的优雅与实用
|
28天前
|
数据采集 算法 数据处理
Python集合推导式的深度探索与实际应用
Python集合推导式的深度探索与实际应用

热门文章

最新文章