Alan Hou的个人博客

第七章 文本处理和正则表达式

精通Python自动化脚本-运维人员宝典完整目录:

第一章 Python脚本概述
第二章 Python脚本调试和性能测试
第三章 单元测试-单元测试框架的介绍
第四章 自动化常规运维活动
第五章 文件、目录和数据处理
第六章 文件存档、加密和解密
第七章 文本处理和正则表达式
第八章 文档和报告
第九章 操作各类文件
第十章 网络基础 – Socket编程
第十一章 使用Python脚本处理邮件
第十二章 使用Telnet和SSH远程监控主机
第十三章 创建图形化用户界面
第十四章 处理Apache和其它的日志文件
第十五章 SOAP和REST API通讯
第十六章 网络抓取 – 从网站上提取有用的信息
第十七章 数据收集及报表
第十八章 MySQL和SQLite数据库管理

本章中我们将学习文本处理和正则表达式。文本处理是一个创建和修改文本的过程。Python有一个称为正则表达式的强大的库,可处理搜索和提取数据等任务。我们将学习如何对文件使用它,同时学习如何读取和写入文件。

我们将学习Python的正则表达式模块re,以及在Python中处理文件。同时学习re模块中的match(), search(), findall()和sub()函数。我们还将使用textwrap来学习Python中的文本封装。最后,我们会学习unicode字符。

本章中我们会学习如何课题:

文本封装

本章中我们将学习Python的textwrap模块。该模块提供了TextWrapper来完成所有任务。textwrap模块用于格式化或封装普通文本。该模块提供了5个主要的函数:wrap(), fill(), dedent(), indent()和shorten()。下面我们将逐一来学习这些函数。

wrap()函数

wrap()函数用于将整个段落封装为单个字符串。输出结果是一个输出行列表。

语法为textwrap.wrap(text, width):

下面我们来看一个wrap()的示例。创建一个脚本wrap_example.py并编写如下内容:

运行脚本,将会得到如下输出:

上例中我们使用了Python中的textwrap模块。首先我们创建一个名为sample_string的字符串。接着我们使用TextWrapper类指定了width。再后使用了wrap函数,字符串被封装长度30。最后我们打印出了各行。

fill()函数

fill()函数与textwrap.wrap的作用相似,只是它返回的数据是连接的、以新行分隔的字符串。该函数将输入封装为文本并返回包含封装文本的单个字符串。

该函数的语法为:textwrap.fill(text, width)

下面我们来看一个fill()的示例。创建一个fill_example.py脚本并编写如下内容:

运行脚本,我们将得到如下输出;

上例中我们使用了fill()函数。整个过程和我们在wrap()中的操作相同。首先,我们创建了一个字符串变量。接着我们创建了一个textwrap对象。然后,我们应用了fill()函数。最后,我们打印了输出。

dedent()函数

dedent()是textwrap模块中的另一个函数。该函数将我们文本每一行的普通前置空格进行移除。

该函数的语法如下:

textwrap.dedent(text)

其中text为取消缩进的文本。

下面我们来看一个dedent()的示例。创建一个脚本dedent_example.py并编写如下内容:

运行脚本,我们将得到如下输出:

上例中,我们创建了一个字符串变量str1。然后我们使用了textwrap.dedent()来移除了常见前置空白内容。制表符和空格都可视作空白内容,但两者并不等价。因此,本例中的对唯一空白内容 tag 进行了删除。

indent()函数

indent()函数用于在文本选择定行的起始处添加指定前置内容。

该函数的语法为:textwrap.indent(text, prefix)

创建一个脚本indent_example.py并编写如下内容:

运行脚本,我们将得到如下输出:

在上例中,我们使用了textwrap模块的fill()和indent()函数。首先,我们使用了fill方法将数据存储在变量w中。接着我们使用了indent方法,输出的每行都会添加一个前缀*。然后我们打印了输出。

shorten()函数

textwraps模块中的这一函数用于截断文本来适配指定的宽度。例如,我们想要创建摘要或预览时,可使用 shorten()函数。使用 shorten()时,文本中所有的空白内容都会被标准化为单个空格。

该函数的语法为:textwrap.shorten(text, width)

下面我们来看一个shorten()的示例。创建一个脚本shorten_example.py并编写如下内容:

运行脚本,我们将得到如下输出:

在上例中,我们使用了shorten()函数来截取文本来适配指定的宽度。首先,所有的空白内容都被截断为单个空格。如果结果符合指定宽度,则会将结果显示在屏幕上。否则,指定宽度的单词会显示在屏幕上,而其余的则放在占位符中。

正则表达式

这一部分中,我们将来学习Python中的正则表达式。正则表达式是一种专用编程语言,内置在Python中,用户可通过re来进行使用。我们为想要匹配的字符串集定义规则 。使用正则表达式,我们可以从文件、代码、文档、电子表格等中提取指定的信息。

在Python中,正则表达式由re表示并可通过re模块来进行导入。正则表达式支持4种内容:

以下表格列出了标识符(identifier),对每一个都有相关的描述:

标识符 描述
\w 匹配字字母数字字符,包含下划线(_)
\W 匹配非字母数字字符,不包含下划线(_)
\d 匹配一个数字
\D 匹配一个非数字字符
\s 匹配一个空格
\S 匹配空格以外的字符
. 匹配一个点号 (.),注:应为任意字符
\b 匹配任意新行以外的字符

下表中列出了修饰符(modifier)以及对应的描述:

修饰符 描述
^ 匹配字符串的起始处
$ 匹配字符串的结尾处
? 匹配0次或11次
* 匹配0次或多次
+  匹配1次或多次
| 匹配两边内容之一x/y
[ ] 范围匹配
{x} 前面标识符的匹配次数

下表中列出了空白字符(whitespace)及相应描述:

字符 描述
\s 空格
\t 制表符 Tab
\n 新起一行
\e 回撤Escape
\f 换页Form feed
\r 返回

以下表格列出了标记及相应描述:

Flag 标记 描述
re.IGNORECASE 忽略大小写匹配
re.DOTALL 匹配包括新行在内的任意字符
re.MULTILINE 多行匹配
Re.ASCII 仅对ASCII字符进行转义匹配

下面我们来看看一些正则表达式的示例。我们将学习match(), search(), findall()和sub()函数。

ℹ️要使用Python中的正则表达式,必须要在脚本中导入re模块,这样才能对正则表达式使用所有的函数和方法。

下面我们就来逐一地学习这些函数。

match()函数

match()是re模块中的一个函数。该函数会将指定的re模式与字符串相匹配。如果找到了匹配,会返回一个匹配对象。匹配对象中包含匹配的相关信息。如果未找到匹配,我们得到的结果是None。match对象有两个方法:

该函数的语法如下:

re.match(pattern, string)

下面我们来看一个re.match()的示例。创建一个脚本re_match.py并编写如下的内容:

运行该脚本,将得到如下输出:

在以上脚本中,我们导入了re模块来在Python中使用正则表达式。然后我们创建了一个字符串str_line。接着我们创建了一个匹配对象obj并在其中存储了模式匹配的结果。本例中,(.*) enjoy (.*?) .*模式会打印出enjoy关键字之前的所有内容,以及只打出enjoy关键字之后的一个单词。然后我们使用了匹配对象的groups()方法。它会打印出元组中的所有匹配子字符串。因此,我闪将得到的输出是(‘This is python tutorial. Do you’, ‘learning’)。

search()函数

re模块中的search()函数会对字符串进行搜索。它会查找re模式中的所有位置。search()会接收一个模式和文本,并在指定的字符串中搜索匹配内容。它会在查找到匹配时会返回一个匹配对象,否则返回None。match对象有两个方法:

该函数的语法如下:

re.search(pattern, string)

创建脚本re_search.py 并编写如下内容:

运行脚本,将会得到如下输出:

上例中,我们使用了匹配对象的search()方法来查找正则模式。在导入re模块后,我们在列表中指定了模式。在该列表中我们编写了两个字符串:programming的hello。接着我们创建了一个字符串:Python programming is fun。我们编写了一个for循环来对指定模式进行逐一检查。如果找到了匹配内容,则执行if代码块,否则执行else代码块。

findall()函数

这是match对象的另一个方法。findall() 方法查找所有的匹配内容,然后以字符串列表的形式返回。列表中的每一个元素代表一个匹配。该方法搜索模式的匹配,并不重叠。

创建一个脚本 re_findall_example.py并编写如下内容:

运行脚本,将得到如下输出:

以上脚本中,我们使用findall() 方法编写了三个示例。第一个示例中,我们定义了一个模式和一个字符串。我们使用findall() 方法在这个字符串查找 该模式,然后进行打印。第二个示例中,我们创建了一个字符串,并使用findall()查找该字符串中前面两个字母为pe的单词,然后进行打印。我们得到了一个前两个字母为pe的单词列表。

此外,我们查找前三个字母为pic的单词并进行打印。这里我们同样将得到一个字符串列表。第三个示例中,我们创建了一个字符串,包含大小写的hello以及单词bye。我们使用findall()查找前两个字母为he的单词。同时在findall()中我们使用了re.IGNORECASE标记来忽略单词的大小写并进行了打印。

sub()函数

这是re模块中最重要的函数之一。sub()用于将指定的替代文本替换掉re模式。它将以替换字符串来替换掉所有re模式发生的内容。语法如下:

re.sub(pattern, repl_str, string, count=0)

下面我们来创建脚本re_sub.py并编写如下内容:

运行脚本,将得到如下输出:

上例中,我们使用了sub()来以指定的字符串来替换re模式。我们以Mary替换了Peter。因此,所有的Peter都以Mary进行了替换。接着,我们增加了count参数。传入了count=1,表示只对Peter进行一次替换,其它的Peter都不进行替换。

下面,我们将学习re模块中的subn()函数。subn()函数和sub()作用相同,并包含更多的功能。subn() 函数返回一个包含新字符串和执行的替换次数的元组。我们来看一个subn() 的示例。创建一个脚本re_subn.py并编写如下内容:

运行脚本,我们将得到如下输出:

上例中,我们使用了subn()函数来替换RE模式。结果我们得到了一个包含替换后文本和替换次数的元组。

Unicode字符串

这一部分中我们将学习如何在Python中打印Unicode字符串。Python可以很轻易地处理Unicode字符串。字符串类型中包含的实际上是Unicode字符串,而非字节序列。

在系统中启动python3终端并编写如下内容:

Unicode代码点

这一部分中,我们将学习unicode代码点(code point)。Python有一个名为ord() 的强大内置函数,可从指定字符获取Unicode代码点。因此我们来看一个从字符获取Unicode代码点的示例,参见如下代码:

编码

将Unicode代码点转换为字节串称为编码。我们来看一个如何对Unicode代码点编码的示例,参见如下代码:

解码

由字节串转换为Unicode代码点称为解码。下面我们来看一个如何对字节串解码获取Unicode代码点的示例,参见如下代码:

避免UnicodeDecodeError

UnicodeDecodeError在字节串无法解码为Unicode代码点时会报出。要避免这一异常,我们可以向decode中错误参数传递replace, backslashreplace或ignore,如下所示:

总结

本章中我们学习了正则表达式,使用它我们可以定义一系列想要匹配字符串的规则。我们也学习了re模块中的四个函数:match(), search(), findall()和sub()。

我们学习了textwrap模块,用于对普通文本进行格式化和封装。我们还学习了textwrap模块中的wrap(), fill(), dedent(), indent()和shorten()函数。最后,我们学习了Unicode字符以及如何在Python中打印Unicode字符串。

下一章中,我们将学习Python中的标准文档和信息报告。

课后问题

  1. Python中的正则表达式是什么?
  2. 编写一个Python程序来检查只包含指定字符集合的字符串(本例中为a–z, A–Z和0–9)。
  3. Python中的哪个模块支持正则表达式?
    a) re
    b) regex
    c) pyregex
    d) 以上都不是
  4. re.match函数的作用是什么?
    a)在字符串起始处匹配模式
    b)在字符中任意位置匹配模式
    c)不存在该函数
    d)以上都不对
  5. 以下的输出是什么?
    语句: “we are humans”
    匹配:re.match(r'(.*) (.*?) (.*)’, sentence)
    a) (‘we’, ‘are’, ‘humans’)
    b) (we, are, humans)
    c) (‘we’, ‘humans’)
    d) ‘we are humans’

扩展阅读

退出移动版