Python正则表达式模式

本文介绍了Python中正则表达式的使用,包括模式字符串的特殊语法,如何匹配函数和变量,以及在实际脚本中生成数据集的应用。示例代码展示了如何统计文件中的函数名与变量名,并提供了一个生成包含日期、邮箱和整数集的字符串数据集的脚本。

在 Python 程序中,模式字符串使用如下特殊的语法来表示一个正则表达式:

  • 字母和数字表示它们自身,一个正则表达式模式中的字母和数字匹配同样的字符串;
  • 当大多数字母和数字前加一个反斜杠时,它们会拥有不同的含义;
  • 标点符号只有被转义时才匹配自身,否则它们表示特殊的含义;
  • 反斜杠本身需要使用反斜杠转义;
  • 因为正则表达式通常都包含反斜杠,所以最好使用原始字符串来表示它们。模式元素(如r'\t',等价于'\\t')匹配相应的特殊字符。


表 1 列出了正则表达式模式语法中的特殊元素。如果使用模式的同时提供了可选的标志参数,则某些模式元素的含义会发生改变。
 

表 1:正则表达式模式语法中的特殊元素
模式描述
^匹配字符串的开头
$匹配字符串的末尾
.匹配任意字符,除换行符之外,当指定 re.DOTALL 标记时,则可以匹配包括换行符的任意字符
[...]用来表示一组字符,单独列出,如 [amk] 匹配 'a' 'm' 或 'k'
[^...]不在 [] 中的字符,如[^abc] 匹配除 a、b、c 之外的字符
re*匹配 0 个或多个表达式
re+匹配 1 个或多个表达式
re?匹配 0 个或 1 个由前面的正则表达式定义的片段,非贪婪方式
re{ n}精确匹配前面的 n 个表达式
re{ n, m}匹配 n~m 次由前面的正则表达式定义的片段,贪婪方式
a | b匹配 a 或 b
(re)匹配括号内的表达式,也表示一个组
(?imx)

正则表达式包含 3 种可选标志—— I、m 或 x。只影响括号中的区域

(?-imx)正则表达式关闭 I、m 或 x 可选标志。只影响括号中的区域
(?: re)类似于(…),但是不表示一组
(?imx: re)在括号中使用I、m 或 x 可选标志

(?-imx: re)

在括号中不使用 I、m 或 x 可选标志
(?#...)注释
(?= re)前向肯定界定符。如果所含正则表达式以…表示,则在当前位置匹配时成功;否则,失败。一旦所含表达式已经使用,那么模式的剩余部分还要尝试匹配界定符的右边
(?! re)前向否定界定符。与肯定界定符相反,当所含表达式不在字符串当前位置匹配时成功
(?>re)匹配的独立模式,省去回溯
\w匹配字母数字
\W匹配非字母数字
\s匹配任意空白字符,等价于[\t\n\r\f\v]
\S匹配任意非空白字符
\d匹配任意数字,等价于 [0~9]
\D匹配任意非数字
\A匹配字符串开始
\Z匹配字符串结束,如果存在换行,则只匹配到换行前的结束字符串
\z匹配字符串结束
\G设置匹配必须出现在上一个匹配结束的地方
\b匹配一个单词边界,也就是指单词和空格间的位置。例如,'er\b'可以匹配 "never" 中的 'er',但不能匹配 "verb" 中的 'er'
\B匹配非单词边界,'er\B' 能匹配"verb"中的' er' ,但不能匹配 "never" 中的 'er'
\n、\t分别用于匹配一个换行符和一个制表符
\1...\9匹配第 n 个分组的子表达式
\10如果正在被匹配,则匹配第 n 个分组的子表达式;否则,指八进制字符码的表达式


表 2 列出了在 Python 程序中使用常用正则表达式的实例。
 

表 2:使用常用正则表达式的实例
实例描述
python匹配 “python”
[Pp]ython

匹配“Python”或“python”

rub[ye]匹配“ruby”或“rube”
[aeiou]匹配中括号内的任意一个字母
[0-9]匹配任何数字,类似于 [0123456789]
[a-z]匹配任何小写字母
[A-Z]匹配任何大写字母
[a-zA-Z0-9]匹配任何字母及数字
[^aeiou]匹配除 a、e、i、o 和 u 字母以外的所有字符
[^0-9]匹配除数字之外的字符
.匹配除“\n”的任何单个字符。要匹配包括在内的任何字符,使用像的模式
\d匹配一个数字字符,等价于[0~9]
\D

匹配一个非数字字符,等价于[^0~9]

\s

匹配任何非空白字符,等价于[^\f\n\r\t\v]

\w匹配包括下画线的任何单词字符,等价于'[A-Za-z0-9_]'
\W匹配任何非单词字符,等价于'[^A-Za-z0-9_]'


下面的实例文件 cao.py 演示了使用正则表达式统计指定文件中函数和变量的过程。Python 语法规定,函数定义必须以“def”开头,为了降低实例的难度,在此假设 Python 函数的编写规范是在关键字“def”后跟一个空格,然后是函数名和参数。没有考虑使用多个空格的情况。

在Python程序中,因为变量一般不需要事先声明,可以直接赋值,所以要想统计文件中的变量信息,需要先处理变量直接赋值的情况,然后通过匹配单词后接“=”的情况查找变量名。为了简化起见,仅考虑比较规范整洁的写法,即规定变量名与“=”之间有一个空格。

另外,添加了一种在 for 循环语句中直接使用的变量类型,在实例中特别处理了 for 循环的情况。在这里,实例并没有处理变量名重复的情况。

import re #导入模块re
import sys #导入模块 sys
def TongjiFunc(s): #定义函数TongjiFunc()统计函数
    r = re.compile( r'''   #调用函数compile()
        (?<=def\s)  #设置前面必须有函数标志 def,并且紧跟一个空格
        \w+   #匹配函数名
        \(.*?\) #匹配参数 、
        (?=:) #后面紧跟一个冒号“:”
        ''',re.X | re.U) #设置编译选项,忽略模式中的注释
    return r.findall(s)

def TongjiVar(s): #定义函数TongjiVar()统计变量
    vars = [] #定义存储变量的列表
    r = re.compile(r'''
        \b #匹配单词
        \w+ #匹配变量名
        (?=\s=) #处理特殊情况—— 变量赋值
        ''',re.X | re.U)    #设置编译选项,忽略模式中的注释
    vars.extend(r.findall(s))
    r = re.compile( r''' 
        (?<=for\s)  #处理for语句中的变量
        \w+   #匹配变量名
        \s  #匹配空格
        (?=in)   #匹配in关键字
        ''',re.X | re.U)    #设置编译选项,忽略模式中的注释
    vars.extend(r.findall(s))
    return vars
if len(sys.argv) == 1: #判断是否输入了命令,如果没有输入,必须输入要处理的文件
    sour = input('亲,请输入文件路径') #提示输入要处理文件的路径
else:  #如果输入了命令
    sour = sys.argv[1] #获取命令行参数
file = open(sour,encoding="utf-8") #打开文件
s = file.readlines() #以行读取文件的内容
file.close() #关闭文件
print('********************************')
print('文件',sour,'中存在的函数有:')
print('********************************')
i = 0   #i表示函数所在的行号
for line in s: #循环遍历文件的内容,匹配里面的函数,输出函数所在的行号,输出函数的原型
    i = i + 1
    function = TongjiFunc(line) #调用统计函数的函数
    if len(function) == 1: #如果行数是1
        print('Line: ',i,'\t',function[0])
print('********************************')
print('文件',sour,'存在的变量有:')
print('********************************')
i = 0 #i表示变量所在的行号
for line in s: #循环遍历文件的各行,匹配里面的变量,输出变量所在的行号,输出变量名
    i = i + 1
    var = TongjiVar(line) #调用统计变量的函数
    if len(var) == 1:
        print('Line: ',i,'\t',var[0])

在上述实例代码中,首先定义了一个能够获取文件中函数名的函数 TongjiFunc(s),然后定义了一个能够获取变量名的函数 TongjiVar(s),最后分别调用它们执行查找和获取操作。执行文件 cao.py 后的效果如图 1 所示。

 

图 1:执行文件 cao.py 后的效果


下面的实例 gaoji1.py 演示了如何创建一个生成数据集的脚本。

from random import randrange, choice 
from string import ascii_lowercase as lc 
from sys import maxsize 
from time import ctime
    ①tlds = ( 'com', 'edu', 'net', 'org', 'gov' )
    for i in range(randrange(5, 11)):
        dtint = randrange(maxsize) #选择日期
        dtstr = ctime(dtint) #日期字符串
     ② llen = randrange(4, 7) #登录名比较短
        login = ''.join(choice(lc) for j in range(llen))
        dlen = randrange(llen, 13) #域比较长
        dom = ''.join(choice(lc)  for j in range(dlen))
        print('%s::%s@%s.%s::%d-%d-%d' % (dtstr, login,dom, choice(tlds), dtint, llen, dlen))

 上述代码是一个生成数据集的脚本,能够简单地将生成的字符串集显示到标准输出中,该输出很容易重定向到测试文件。上述脚本能够生成拥有 3 个字段的字符串,由一对冒号:或者一对双冒号::分隔。其中第一个字段是随机(32 位)整数,该整数将被转换为一个日期;第 2 个字段是一个随机生成的电子邮件地址;第3个字段是一个由单横线-分隔的整数集。

其中 tlds 是由一组高级域名格式组合而成的,当需要随机生成电子邮件地址时,可以从中随机选出一个。每当执行文件 gendata.py,就会生成 for 语句之前的输出(该脚本对于所有需要随机整数的场景都使用函数 random.randrange())。对于每一行,选取范围(0~231−1) 中所有可能的随机整数,然后使用函数 time.ctime() 将该整数转换为日期。

在 Python 程序中,系统时间和大多数基于 POSIX 的计算机一样,两者都使用从“epoch”到今天的秒数,其中 epoch 是指 1970 年 1 月 1 日格林尼治时间的午夜。如果选择一个 32 位整数,那么该整数将表示从epoch到最大可能时间(即epoch后的232s)之间的某个时刻。

①~② 的功能是构造登录名长度是 4~7 个字符的邮件地址,这是通过使用 randrange(4,8) 实现的。为了将它们放在一起,需要随机选择 4~7 个小写字母,将所有字母逐个连接成一个字符串。函数 random.choice() 的功能就是接受一个序列,然后返回该序列中的一个随机元素。在上述代码中,string.ascii_lowercase 是字母表里拥有 26 个小写字母的序列集合。

注意:不能将限定符与定位点一起使用。

在 Python 程序中,因为在换行符或者字边界的前面或后面不能有一个以上空的位置,所以不允许诸如^*之类的表达式。如果要匹配一行文本开始处的字符,请在正则表达式的开始使用^字符。不要将^的这种用法与中括号表达式内的用法混淆。如果要匹配一行文本结束处的字符,请在正则表达式的结束处使用$字符。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wwwarewow

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值