《Python Cookbook(第2版)中文版》——1.16 替换字符串中的子串

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

1.16 替换字符串中的子串

任务

需要一个简单的方法来完成这样一个任务:给定一个字符串,通过查询一个替换字典,将字符串中被标记的子字符串替换掉。

解决方案

下面给出的解决办法既适用于Python 2.3,也适用于2.4:

def expand(format, d, marker='"', safe=False):
      if safe:
             def lookup(w): return d.get(w, w.join(marker*2))
      else:
             def lookup(w): return d[w]
      parts = format.split(marker)
      parts[1::2] = map(lookup, parts[1::2])
      return ''.join(parts)
if _ _name_ _ == '_ _main_ _':
      print expand('just "a" test', {'a': 'one'})
# 输出:just one test

如果参数safe是False,则默认条件下,字符串中所有被标记的子字符串必须能够在字典d中找到,否则,expand会抛出一个KeyError异常并终止执行。当参数safe被明确指定为True时,如果被标记的子字符串在字典中找不到,则被标记的部分也不会被改变。

讨论

expand函数代码的主体部分有个很有趣的地方:根据操作是否被要求为安全,它使用两个不同的嵌套函数(两者有着同样的名字lookup)中的一个。安全意味着被标记的子字符串应该能够在字典查到,如果查不到,不抛出KeyError异常。如果这个函数并不是必须安全的(默认情况下不安全),lookup根据索引访问字典d,并在该索引(子字符串)不存在的时候抛出个错误。但如果lookup被要求为安全的,它将使用d的方法get,get返回根据索引能够查到的值,若找不到就返回在两边加上了标记的被查询的子字符串。给safe传入True,表明你宁可看到输出中有标记符也不愿看到异常信息。marker+w+marker是可以替换w.join(marker*2)的另一种方式,但我采用后者的原因是,它展示了一种不太简明却很有意思的构造带引号字符串的方法。

不管用哪个版本的lookup,expand都会执行切分、修改、拼接—这些在Python的字符串处理中最重要的操作。在expand中进行修改的部分,使用了指定了步长的列表切片方法。确切地说,expand访问并重新绑定了parts的奇数索引的项,因为这些项正好是原字符串中位于两个标记符之间的部分。因此,它们就是被标记的子字符串,也就是需要在字典中查找的字符串。

本节解决方案给出的expand函数接受非常灵活的字符串语法形式,比基于$的string.Template更灵活。你如果想让输出字符串包括双引号,也可以指定其他的标记符。当然,函数也没有限制被标记的子串不能是标识符,可以轻松地插入Python表达式(d的 _getitem _方法会执行eval操作)或者任意其他占位符。而且,还可以轻易地搞出点有些不同的更有趣的效果,比如:

print expand('just "a" ""little"" test', {'a' : 'one', '' : '"'})

输出结果是just one "little" test。高级用户可以定制Python 2.4的string.Template类,通过继承来实现上述的所有功能,甚至更多其他高级功能。但本节解决方案中的小巧的expand函数却更加简洁易用。

上一篇:Juc20_Synchronized锁升级、无锁、偏向锁、轻量级锁、重量级锁、锁消除、锁粗化(三)


下一篇:详解标识符和关键字 | 手把手教你入门Python之十四