python字符串和文本处理

2.1 使用多个界定符分割字符串

问题
你需要将一个字符串分割为多个字段,但是分隔符(还有周围的空格)并不是固定的。

解决方案
string 对象的 split() 方法只适应于非常简单的字符串分割情形, 它并不允许有多个分隔符或者是分隔符周围不确定的空格。 当你需要更加灵活的切割字符串的时候,最好使用 re.split() 方法:
在这里插入图片描述
讨论
函数 re.split() 是非常实用的,因为它允许你为分隔符指定多个正则模式。 比如,在上面的例子中,分隔符可以是逗号,分号或者是空格,并且后面紧跟着任意个的空格。 只要这个模式被找到,那么匹配的分隔符两边的实体都会被当成是结果中的元素返回。 返回结果为一个字段列表,这个跟 str.split() 返回值类型是一样的。

当你使用 re.split() 函数时候,需要特别注意的是正则表达式中是否包含一个括号捕获分组。 如果使用了捕获分组,那么被匹配的文本也将出现在结果列表中。比如,观察一下这段代码运行后的结果:
在这里插入图片描述
获取分割字符在某些情况下也是有用的。 比如,你可能想保留分割字符串,用来在后面重新构造一个新的输出字符串:
在这里插入图片描述
如果你不想保留分割字符串到结果列表中去,但仍然需要使用到括号来分组正则表达式的话, 确保你的分组是非捕获分组,形如 (?:…) 。比如:
在这里插入图片描述

2.2 字符串开头或结尾匹配

问题
你需要通过指定的文本模式去检查字符串的开头或者结尾,比如文件名后缀,URL Scheme等等。

解决方案
检查字符串开头或结尾的一个简单方法是使用 str.startswith() 或者是 str.endswith() 方法。比如:
在这里插入图片描述
如果你想检查多种匹配可能,只需要将所有的匹配项放入到一个元组中去, 然后传给 startswith() 或者 endswith() 方法:
在这里插入图片描述
下面是另一个例子:
在这里插入图片描述
奇怪的是,这个方法中必须要输入一个元组作为参数。 如果你恰巧有一个 list 或者 set 类型的选择项, 要确保传递参数前先调用 tuple() 将其转换为元组类型。比如:
在这里插入图片描述
讨论
startswith() 和 endswith() 方法提供了一个非常方便的方式去做字符串开头和结尾的检查。 类似的操作也可以使用切片来实现,但是代码看起来没有那么优雅。比如:
在这里插入图片描述
你可以能还想使用正则表达式去实现,比如:
在这里插入图片描述
这种方式也行得通,但是对于简单的匹配实在是有点小材大用了,本节中的方法更加简单并且运行会更快些。

最后提一下,当和其他操作比如普通数据聚合相结合的时候 startswith() 和 endswith() 方法是很不错的。 比如,下面这个语句检查某个文件夹中是否存在指定的文件类型:
在这里插入图片描述

2.3 用Shell通配符匹配字符串

问题
你想使用 Unix Shell 中常用的通配符(比如 .py , Dat[0-9].csv 等)去匹配文本字符串

解决方案
fnmatch 模块提供了两个函数—— fnmatch() 和 fnmatchcase() ,可以用来实现这样的匹配。用法如下:
在这里插入图片描述
fnmatch() 函数使用底层操作系统的大小写敏感规则(不同的系统是不一样的)来匹配模式。比如:
在这里插入图片描述
如果你对这个区别很在意,可以使用 fnmatchcase() 来代替。它完全使用你的模式大小写匹配。比如:
在这里插入图片描述
这两个函数通常会被忽略的一个特性是在处理非文件名的字符串时候它们也是很有用的。 比如,假设你有一个街道地址的列表数据:
在这里插入图片描述

你可以像这样写列表推导:
在这里插入图片描述
讨论
fnmatch() 函数匹配能力介于简单的字符串方法和强大的正则表达式之间。 如果在数据处理操作中只需要简单的通配符就能完成的时候,这通常是一个比较合理的方案。

如果你的代码需要做文件名的匹配,最好使用 glob 模块。参考5.13小节。

2.4 字符串匹配和搜索

问题
你想匹配或者搜索特定模式的文本

解决方案
如果你想匹配的是字面字符串,那么你通常只需要调用基本字符串方法就行, 比如 str.find() , str.endswith() , str.startswith() 或者类似的方法:
在这里插入图片描述
对于复杂的匹配需要使用正则表达式和 re 模块。 为了解释正则表达式的基本原理,假设你想匹配数字格式的日期字符串比如 11/27/2012 ,你可以这样做:
在这里插入图片描述
如果你想使用同一个模式去做多次匹配,你应该先将模式字符串预编译为模式对象。比如:
在这里插入图片描述
match() 总是从字符串开始去匹配,如果你想查找字符串任意部分的模式出现位置, 使用 findall() 方法去代替。比如:
在这里插入图片描述
在定义正则式的时候,通常会利用括号去捕获分组。比如:
在这里插入图片描述
捕获分组可以使得后面的处理更加简单,因为可以分别将每个组的内容提取出来。比如:
在这里插入图片描述
findall() 方法会搜索文本并以列表形式返回所有的匹配。 如果你想以迭代方式返回匹配,可以使用 finditer() 方法来代替,比如:
在这里插入图片描述
讨论
关于正则表达式理论的教程已经超出了本书的范围。 不过,这一节阐述了使用re模块进行匹配和搜索文本的最基本方法。 核心步骤就是先使用 re.compile() 编译正则表达式字符串, 然后使用 match() , findall() 或者 finditer() 等方法。

当写正则式字符串的时候,相对普遍的做法是使用原始字符串比如 r’(\d+)/(\d+)/(\d+)’ 。 这种字符串将不去解析反斜杠,这在正则表达式中是很有用的。 如果不这样做的话,你必须使用两个反斜杠,类似 ‘(\d+)/(\d+)/(\d+)’ 。

需要注意的是 match() 方法仅仅检查字符串的开始部分。它的匹配结果有可能并不是你期望的那样。比如:
在这里插入图片描述
如果你想精确匹配,确保你的正则表达式以$结尾,就像这么这样:
在这里插入图片描述
最后,如果你仅仅是做一次简单的文本匹配/搜索操作的话,可以略过编译部分,直接使用 re 模块级别的函数。比如:
在这里插入图片描述
但是需要注意的是,如果你打算做大量的匹配和搜索操作的话,最好先编译正则表达式,然后再重复使用它。 模块级别的函数会将最近编译过的模式缓存起来,因此并不会消耗太多的性能, 但是如果使用预编译模式的话,你将会减少查找和一些额外的处理损耗。

2.5 字符串搜索和替换

问题
你想在字符串中搜索和匹配指定的文本模式

解决方案
对于简单的字面模式,直接使用 str.replace() 方法即可,比如:
在这里插入图片描述
对于复杂的模式,请使用 re 模块中的 sub() 函数。 为了说明这个,假设你想将形式为 11/27/2012 的日期字符串改成 2012-11-27 。示例如下:
在这里插入图片描述
sub() 函数中的第一个参数是被匹配的模式,第二个参数是替换模式。反斜杠数字比如 \3 指向前面模式的捕获组号。

如果你打算用相同的模式做多次替换,考虑先编译它来提升性能。比如:
在这里插入图片描述
对于更加复杂的替换,可以传递一个替换回调函数来代替,比如:
在这里插入图片描述
一个替换回调函数的参数是一个 match 对象,也就是 match() 或者 find() 返回的对象。 使用 group() 方法来提取特定的匹配部分。回调函数最后返回替换字符串。

如果除了替换后的结果外,你还想知道有多少替换发生了,可以使用 re.subn() 来代替。比如:
在这里插入图片描述
讨论
关于正则表达式搜索和替换,上面演示的 sub() 方法基本已经涵盖了所有。 其实最难的部分就是编写正则表达式模式,这个最好是留给读者自己去练习了。

2.6 字符串忽略大小写的搜索替换

问题
你需要以忽略大小写的方式搜索与替换文本字符串

解决方案
为了在文本操作时忽略大小写,你需要在使用 re 模块的时候给这些操作提供 re.IGNORECASE 标志参数。比如:
在这里插入图片描述
最后的那个例子揭示了一个小缺陷,替换字符串并不会自动跟被匹配字符串的大小写保持一致。 为了修复这个,你可能需要一个辅助函数,就像下面的这样:

在这里插入图片描述
下面是使用上述函数的方法:
在这里插入图片描述
译者注: matchcase(‘snake’) 返回了一个回调函数(参数必须是 match 对象),前面一节提到过, sub() 函数除了接受替换字符串外,还能接受一个回调函数。

讨论
对于一般的忽略大小写的匹配操作,简单的传递一个 re.IGNORECASE 标志参数就已经足够了。 但是需要注意的是,这个对于某些需要大小写转换的Unicode匹配可能还不够, 参考2.10小节了解更多细节。

2.7 最短匹配模式

问题
你正在试着用正则表达式匹配某个文本模式,但是它找到的是模式的最长可能匹配。 而你想修改它变成查找最短的可能匹配。

解决方案
这个问题一般出现在需要匹配一对分隔符之间的文本的时候(比如引号包含的字符串)。 为了说明清楚,考虑如下的例子:在这里插入图片描述
在这个例子中,模式 r’"(.)"’ 的意图是匹配被双引号包含的文本。 但是在正则表达式中操作符是贪婪的,因此匹配操作会查找最长的可能匹配。 于是在第二个例子中搜索 text2 的时候返回结果并不是我们想要的。

为了修正这个问题,可以在模式中的*操作符后面加上?修饰符,就像这样:
在这里插入图片描述
这样就使得匹配变成非贪婪模式,从而得到最短的匹配,也就是我们想要的结果。
讨论
这一节展示了在写包含点(.)字符的正则表达式的时候遇到的一些常见问题。 在一个模式字符串中,点(.)匹配除了换行外的任何字符。 然而,如果你将点(.)号放在开始与结束符(比如引号)之间的时候,那么匹配操作会查找符合模式的最长可能匹配。 这样通常会导致很多中间的被开始与结束符包含的文本被忽略掉,并最终被包含在匹配结果字符串中返回。 通过在 * 或者 + 这样的操作符后面添加一个 ? 可以强制匹配算法改成寻找最短的可能匹配

2.8 多行匹配模式

问题
你正在试着使用正则表达式去匹配一大块的文本,而你需要跨越多行去匹配。

解决方案
这个问题很典型的出现在当你用点(.)去匹配任意字符的时候,忘记了点(.)不能匹配换行符的事实。 比如,假设你想试着去匹配C语言分割的注释:在这里插入图片描述
为了修正这个问题,你可以修改模式字符串,增加对换行的支持。比如:
在这里插入图片描述
在这个模式中, (?:.|\n) 指定了一个非捕获组 (也就是它定义了一个仅仅用来做匹配,而不能通过单独捕获或者编号的组)。
讨论
re.compile() 函数接受一个标志参数叫 re.DOTALL ,在这里非常有用。 它可以让正则表达式中的点(.)匹配包括换行符在内的任意字符。比如:
在这里插入图片描述
对于简单的情况使用 re.DOTALL 标记参数工作的很好, 但是如果模式非常复杂或者是为了构造字符串令牌而将多个模式合并起来(2.18节有详细描述), 这时候使用这个标记参数就可能出现一些问题。 如果让你选择的话,最好还是定义自己的正则表达式模式,这样它可以在不需要额外的标记参数下也能工作的很好。

2.9 将Unicode文本标准化

问题
你正在处理Unicode字符串,需要确保所有字符串在底层有相同的表示。

解决方案
在Unicode中,某些字符能够用多个合法的编码表示。为了说明,考虑下面的这个例子:
在这里插入图片描述
这里的文本”Spicy Jalapeño”使用了两种形式来表示。 第一种使用整体字符”ñ”(U+00F1),第二种使用拉丁字母”n”后面跟一个”~”的组合字符(U+0303)。

在需要比较字符串的程序中使用字符的多种表示会产生问题。 为了修正这个问题,你可以使用unicodedata模块先将文本标准化:
在这里插入图片描述
normalize() 第一个参数指定字符串标准化的方式。 NFC表示字符应该是整体组成(比如可能的话就使用单一编码),而NFD表示字符应该分解为多个组合字符表示。

Python同样支持扩展的标准化形式NFKC和NFKD,它们在处理某些字符的时候增加了额外的兼容特性。比如:
在这里插入图片描述
讨论
标准化对于任何需要以一致的方式处理Unicode文本的程序都是非常重要的。 当处理来自用户输入的字符串而你很难去控制编码的时候尤其如此。

在清理和过滤文本的时候字符的标准化也是很重要的。 比如,假设你想清除掉一些文本上面的变音符的时候(可能是为了搜索和匹配):
在这里插入图片描述
最后一个例子展示了 unicodedata 模块的另一个重要方面,也就是测试字符类的工具函数。 combining() 函数可以测试一个字符是否为和音字符。 在这个模块中还有其他函数用于查找字符类别,测试是否为数字字符等等。

Unicode显然是一个很大的主题。如果想更深入的了解关于标准化方面的信息, 请看考 Unicode官网中关于这部分的说明 Ned Batchelder在 他的网站 上对Python的Unicode处理问题也有一个很好的介绍。

2.10 在正则式中使用Unicode

问题
你正在使用正则表达式处理文本,但是关注的是Unicode字符处理。

解决方案
默认情况下 re 模块已经对一些Unicode字符类有了基本的支持。 比如, \d 已经匹配任意的unicode数字字符了:
在这里插入图片描述
如果你想在模式中包含指定的Unicode字符,你可以使用Unicode字符对应的转义序列(比如 \uFFF 或者 \UFFFFFFF )。 比如,下面是一个匹配几个不同阿拉伯编码页面中所有字符的正则表达式:
在这里插入图片描述
当执行匹配和搜索操作的时候,最好是先标准化并且清理所有文本为标准化格式(参考2.9小节)。 但是同样也应该注意一些特殊情况,比如在忽略大小写匹配和大小写转换时的行为。
在这里插入图片描述
讨论
混合使用Unicode和正则表达式通常会让你抓狂。 如果你真的打算这样做的话,最好考虑下安装第三方正则式库, 它们会为Unicode的大小写转换和其他大量有趣特性提供全面的支持,包括模糊匹配。

2.11 删除字符串中不需要的字符

问题
你想去掉文本字符串开头,结尾或者中间不想要的字符,比如空白。

解决方案
strip() 方法能用于删除开始或结尾的字符。 lstrip() 和 rstrip() 分别从左和从右执行删除操作。 默认情况下,这些方法会去除空白字符,但是你也可以指定其他字符。比如:
在这里插入图片描述
讨论
这些 strip() 方法在读取和清理数据以备后续处理的时候是经常会被用到的。 比如,你可以用它们来去掉空格,引号和完成其他任务。

但是需要注意的是去除操作不会对字符串的中间的文本产生任何影响。比如:
在这里插入图片描述
如果你想处理中间的空格,那么你需要求助其他技术。比如使用 replace() 方法或者是用正则表达式替换。示例如下:
在这里插入图片描述
通常情况下你想将字符串 strip 操作和其他迭代操作相结合,比如从文件中读取多行数据。 如果是这样的话,那么生成器表达式就可以大显身手了。比如:
在这里插入图片描述
在这里,表达式 lines = (line.strip() for line in f) 执行数据转换操作。 这种方式非常高效,因为它不需要预先读取所有数据放到一个临时的列表中去。 它仅仅只是创建一个生成器,并且每次返回行之前会先执行 strip 操作。

对于更高阶的strip,你可能需要使用 translate() 方法。请参阅下一节了解更多关于字符串清理的内容。

2.12 审查清理文本字符串

问题
一些无聊的幼稚黑客在你的网站页面表单中输入文本”pýtĥöñ”,然后你想将这些字符清理掉。

解决方案
文本清理问题会涉及到包括文本解析与数据处理等一系列问题。 在非常简单的情形下,你可能会选择使用字符串函数(比如 str.upper() 和 str.lower() )将文本转为标准格式。 使用 str.replace() 或者 re.sub() 的简单替换操作能删除或者改变指定的字符序列。 你同样还可以使用2.9小节的 unicodedata.normalize() 函数将unicode文本标准化。

然后,有时候你可能还想在清理操作上更进一步。比如,你可能想消除整个区间上的字符或者去除变音符。 为了这样做,你可以使用经常会被忽视的 str.translate() 方法。 为了演示,假设你现在有下面这个凌乱的字符串:
在这里插入图片描述
第一步是清理空白字符。为了这样做,先创建一个小的转换表格然后使用 translate() 方法:
在这里插入图片描述
正如你看的那样,空白字符 \t 和 \f 已经被重新映射到一个空格。回车字符r直接被删除。

你可以以这个表格为基础进一步构建更大的表格。比如,让我们删除所有的和音符:
在这里插入图片描述
上面例子中,通过使用 dict.fromkeys() 方法构造一个字典,每个Unicode和音符作为键,对应的值全部为 None 。

然后使用 unicodedata.normalize() 将原始输入标准化为分解形式字符。 然后再调用 translate 函数删除所有重音符。 同样的技术也可以被用来删除其他类型的字符(比如控制字符等)。

作为另一个例子,这里构造一个将所有Unicode数字字符映射到对应的ASCII字符上的表格:
在这里插入图片描述
另一种清理文本的技术涉及到I/O解码与编码函数。这里的思路是先对文本做一些初步的清理, 然后再结合 encode() 或者 decode() 操作来清除或修改它。比如:
在这里插入图片描述
这里的标准化操作将原来的文本分解为单独的和音符。接下来的ASCII编码/解码只是简单的一下子丢弃掉那些字符。 当然,这种方法仅仅只在最后的目标就是获取到文本对应ACSII表示的时候生效。

讨论
文本字符清理一个最主要的问题应该是运行的性能。一般来讲,代码越简单运行越快。 对于简单的替换操作, str.replace() 方法通常是最快的,甚至在你需要多次调用的时候。 比如,为了清理空白字符,你可以这样做:
在这里插入图片描述
如果你去测试的话,你就会发现这种方式会比使用 translate() 或者正则表达式要快很多。

另一方面,如果你需要执行任何复杂字符对字符的重新映射或者删除操作的话, tanslate() 方法会非常的快。

从大的方面来讲,对于你的应用程序来说性能是你不得不去自己研究的东西。 不幸的是,我们不可能给你建议一个特定的技术,使它能够适应所有的情况。 因此实际情况中需要你自己去尝试不同的方法并评估它。

尽管这一节集中讨论的是文本,但是类似的技术也可以适用于字节,包括简单的替换,转换和正则表达式。

2.13 字符串对齐

问题
你想通过某种对齐方式来格式化字符串

解决方案
对于基本的字符串对齐操作,可以使用字符串的 ljust() , rjust() 和 center() 方法。比如:
在这里插入图片描述
所有这些方法都能接受一个可选的填充字符。比如:
在这里插入图片描述
函数 format() 同样可以用来很容易的对齐字符串。 你要做的就是使用 <,> 或者 ^ 字符后面紧跟一个指定的宽度。比如:
在这里插入图片描述
如果你想指定一个非空格的填充字符,将它写到对齐字符的前面即可:
在这里插入图片描述
当格式化多个值的时候,这些格式代码也可以被用在 format() 方法中。比如:
在这里插入图片描述
format() 函数的一个好处是它不仅适用于字符串。它可以用来格式化任何值,使得它非常的通用。 比如,你可以用它来格式化数字:
在这里插入图片描述
讨论
在老的代码中,你经常会看到被用来格式化文本的 % 操作符。比如:
在这里插入图片描述
但是,在新版本代码中,你应该优先选择 format() 函数或者方法。 format() 要比 % 操作符的功能更为强大。 并且 format() 也比使用 ljust() , rjust() 或 center() 方法更通用, 因为它可以用来格式化任意对象,而不仅仅是字符串。

如果想要完全了解 format() 函数的有用特性, 请参考 在线Python文档

2.14 合并拼接字符串

问题
你想将几个小的字符串合并为一个大的字符串

解决方案
如果你想要合并的字符串是在一个序列或者 iterable 中,那么最快的方式就是使用 join() 方法。比如:
在这里插入图片描述
初看起来,这种语法看上去会比较怪,但是 join() 被指定为字符串的一个方法。 这样做的部分原因是你想去连接的对象可能来自各种不同的数据序列(比如列表,元组,字典,文件,集合或生成器等), 如果在所有这些对象上都定义一个 join() 方法明显是冗余的。 因此你只需要指定你想要的分割字符串并调用他的 join() 方法去将文本片段组合起来。

如果你仅仅只是合并少数几个字符串,使用加号(+)通常已经足够了:
在这里插入图片描述
加号(+)操作符在作为一些复杂字符串格式化的替代方案的时候通常也工作的很好,比如:
在这里插入图片描述
如果你想在源码中将两个字面字符串合并起来,你只需要简单的将它们放到一起,不需要用加号(+)。比如:
在这里插入图片描述
讨论
字符串合并可能看上去并不需要用一整节来讨论。 但是不应该小看这个问题,程序员通常在字符串格式化的时候因为选择不当而给应用程序带来严重性能损失。

最重要的需要引起注意的是,当我们使用加号(+)操作符去连接大量的字符串的时候是非常低效率的, 因为加号连接会引起内存复制以及垃圾回收操作。 特别的,你永远都不应像下面这样写字符串连接代码:
在这里插入图片描述
这种写法会比使用 join() 方法运行的要慢一些,因为每一次执行+=操作的时候会创建一个新的字符串对象。 你最好是先收集所有的字符串片段然后再将它们连接起来。

一个相对比较聪明的技巧是利用生成器表达式(参考1.19小节)转换数据为字符串的同时合并字符串,比如:
在这里插入图片描述
同样还得注意不必要的字符串连接操作。有时候程序员在没有必要做连接操作的时候仍然多此一举。比如在打印的时候:
在这里插入图片描述
当混合使用I/O操作和字符串连接操作的时候,有时候需要仔细研究你的程序。 比如,考虑下面的两端代码片段:
在这里插入图片描述
如果两个字符串很小,那么第一个版本性能会更好些,因为I/O系统调用天生就慢。 另外一方面,如果两个字符串很大,那么第二个版本可能会更加高效, 因为它避免了创建一个很大的临时结果并且要复制大量的内存块数据。 还是那句话,有时候是需要根据你的应用程序特点来决定应该使用哪种方案。

最后谈一下,如果你准备编写构建大量小字符串的输出代码, 你最好考虑下使用生成器函数,利用yield语句产生输出片段。比如:
在这里插入图片描述
这种方法一个有趣的方面是它并没有对输出片段到底要怎样组织做出假设。 例如,你可以简单的使用 join() 方法将这些片段合并起来:
在这里插入图片描述
或者你也可以将字符串片段重定向到I/O:
在这里插入图片描述
再或者你还可以写出一些结合I/O操作的混合方案:
在这里插入图片描述
这里的关键点在于原始的生成器函数并不需要知道使用细节,它只负责生成字符串片段就行了。

2.15 字符串中插入变量

问题
你想创建一个内嵌变量的字符串,变量被它的值所表示的字符串替换掉。

解决方案
Python并没有对在字符串中简单替换变量值提供直接的支持。 但是通过使用字符串的 format() 方法来解决这个问题。比如:
在这里插入图片描述
或者,如果要被替换的变量能在变量域中找到, 那么你可以结合使用 format_map() 和 vars() 。就像下面这样:
在这里插入图片描述
vars() 还有一个有意思的特性就是它也适用于对象实例。比如:
在这里插入图片描述
format 和 format_map() 的一个缺陷就是它们并不能很好的处理变量缺失的情况,比如:
在这里插入图片描述
一种避免这种错误的方法是另外定义一个含有 missing() 方法的字典对象,就像下面这样:
在这里插入图片描述
现在你可以利用这个类包装输入后传递给 format_map() :
在这里插入图片描述
如果你发现自己在代码中频繁的执行这些步骤,你可以将变量替换步骤用一个工具函数封装起来。就像下面这样:
在这里插入图片描述
现在你可以像下面这样写了:
在这里插入图片描述
讨论
多年以来由于Python缺乏对变量替换的内置支持而导致了各种不同的解决方案。 作为本节中展示的一个可能的解决方案,你可以有时候会看到像下面这样的字符串格式化代码:
在这里插入图片描述
你可能还会看到字符串模板的使用:
在这里插入图片描述
然而, format() 和 format_map() 相比较上面这些方案而已更加先进,因此应该被优先选择。 使用 format() 方法还有一个好处就是你可以获得对字符串格式化的所有支持(对齐,填充,数字格式化等待), 而这些特性是使用像模板字符串之类的方案不可能获得的。

本机还部分介绍了一些高级特性。映射或者字典类中鲜为人知的 missing() 方法可以让你定义如何处理缺失的值。 在 SafeSub 类中,这个方法被定义为对缺失的值返回一个占位符。 你可以发现缺失的值会出现在结果字符串中(在调试的时候可能很有用),而不是产生一个 KeyError 异常。

sub() 函数使用 sys._getframe(1) 返回调用者的栈帧。可以从中访问属性 f_locals 来获得局部变量。 毫无疑问绝大部分情况下在代码中去直接操作栈帧应该是不推荐的。 但是,对于像字符串替换工具函数而言它是非常有用的。 另外,值得注意的是 f_locals 是一个复制调用函数的本地变量的字典。 尽管你可以改变 f_locals 的内容,但是这个修改对于后面的变量访问没有任何影响。 所以,虽说访问一个栈帧看上去很邪恶,但是对它的任何操作不会覆盖和改变调用者本地变量的值。

2.16 以指定列宽格式化字符串
问题
你有一些长字符串,想以指定的列宽将它们重新格式化。

解决方案
使用 textwrap 模块来格式化字符串的输出。比如,假如你有下列的长字符串:

s = “Look into my eyes, look into my eyes, the eyes, the eyes,
the eyes, not around the eyes, don’t look around the eyes,
look into my eyes, you’re under.”

下面演示使用 textwrap 格式化字符串的多种方式:
在这里插入图片描述

讨论
textwrap 模块对于字符串打印是非常有用的,特别是当你希望输出自动匹配终端大小的时候。 你可以使用 os.get_terminal_size() 方法来获取终端的大小尺寸。比如:
在这里插入图片描述
但是我自己用python3.6测试的时候这段代码竟然不能运行,出现了如下错误
在这里插入图片描述

2.17 在字符串中处理html和xml

问题
你想将HTML或者XML实体如 &entity; 或 &#code; 替换为对应的文本。 再者,你需要转换文本中特定的字符(比如<, >, 或 &)。

解决方案
如果你想替换文本字符串中的 ‘<’ 或者 ‘>’ ,使用 html.escape() 函数可以很容易的完成。比如:
在这里插入图片描述
如果你正在处理的是ASCII文本,并且想将非ASCII文本对应的编码实体嵌入进去, 可以给某些I/O函数传递参数 errors=‘xmlcharrefreplace’ 来达到这个目。比如:
在这里插入图片描述
为了替换文本中的编码实体,你需要使用另外一种方法。 如果你正在处理HTML或者XML文本,试着先使用一个合适的HTML或者XML解析器。 通常情况下,这些工具会自动替换这些编码值,你无需担心。

有时候,如果你接收到了一些含有编码值的原始文本,需要手动去做替换, 通常你只需要使用HTML或者XML解析器的一些相关工具函数/方法即可。比如:
在这里插入图片描述
讨论
在生成HTML或者XML文本的时候,如果正确的转换特殊标记字符是一个很容易被忽视的细节。 特别是当你使用 print() 函数或者其他字符串格式化来产生输出的时候。 使用像 html.escape() 的工具函数可以很容易的解决这类问题。

如果你想以其他方式处理文本,还有一些其他的工具函数比如 xml.sax.saxutils.unescapge() 可以帮助你。 然而,你应该先调研清楚怎样使用一个合适的解析器。 比如,如果你在处理HTML或XML文本, 使用某个解析模块比如 html.parse 或 xml.etree.ElementTree 已经帮你自动处理了相关的替换细节。

转载来源: https://blog.csdn.net/qq_30500113/article/details/84192999

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页