正则表达式

why what how
why:从大量文本中查找规则字符串,比字符串各种查找都快,利用C语言的匹配引擎,广泛用于各种搜索,查找,爬虫
what:
正则->代数, 变量替换(用一些规定好的符号取匹配有规则的文本)
英文:regular

正则表达式的语法

  • . : 表示任意字符,如果说指定了DOTALL的标识,就表示包括新行在内的所有字符,
  • ^ : 表示字符串开头
  • $ : 表示字符串结尾,例如:’test’可以匹配’test’和’testtool’,但’test$’只能匹配’test’。
  • * , + , ? : 添加到要匹配的目标后面

正则表达 - 图1
正则表达 - 图2
正则表达 - 图3

正则表达 - 图4
正则表达 - 图5

练习工具

国外工具

  • 网址
    www.regexpal.com

    国内工具

  • 开源中国

    • 网址
    • tool.oschina.net/regex
  • 中文字符集范围:/u4e00-/u9fa5

    re模块使用说明(hit and run)

    正则表达 - 图6
    模块内容:
    正则表达 - 图7

    函数

    complie编译函数会返回一个正则表达式regex对象,代表一种匹配关系
    search函数,match函数会返回一种match对象
    split会返回一个列表,分割的结果
    findall返回列表
    finditer返回迭代器
    sub替换函数返回字符串
    subn返回元组
    escape会返回字符串,包含各种正则中的字符
    purge清除函数

    常量:

  • 常量就是前面函数中的flags的内容
    - 常量的大小写一定是严格区分的,代表的含义通常是不同的

    对象:

  • regex对象:

  • match对象

    使用方法示例:

  • import re

  • re.compile()创建一个正则对象regex,一个变量多次使用
  1. 使用regex
    • regex = re.compile(pattern) # regex可以多次使用
    • result = regex.match(string) # 具体使用regex
  2. 使用match
  • match = re.match(pattern, string) # match对象,每次使用都要生成
  • 使用regex查找一个字符串,返回被匹配的 对象
  • 调用匹配对象的group方法,返回实际匹配的 文本

    重点的匹配符和函数的用法

    匹配符

    正则表达 - 图8
    a{m, }表示匹配m个到无限个a
    ###重点函数
    - re.compile(pattern, flags=0)
    正则表达 - 图9
    - re.search(pattern, string, flags=0)
    正则表达 - 图10
    - re.match(pattern, string, flags=0)
    正则表达 - 图11
    match函数与search函数不同,search函数是在一整个字符串中寻找符合模式的,match函数是必须从第一个字符开始匹配,如果第一个匹配上在匹配第二个,直到所有的都匹配上才算匹配上

    如果想分组匹配

    分组的实现方式是给正则表达式加上(),就可以让括号内的单独成为一个正则表达式(并且会根据括号出现的位置给每一个括号赋予序号,可以用于字符串的重组替换)

    IP地址的匹配

  • 错误的方式:

(\d[1,3].){3}\d[1,3]
这种方式会匹配到大于255的情况

  • 正确的方式

r’((2[0-4]\d|25[0-5]|[01]?\d\d?).){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)

注意命名规则

比如用regex匹配IP
re_ip = re.compile(r’’’
((2[0-4]\d # 200-249
|25[0-5] # 250-255
|[01]?\d\d?).){3} # 0-199 这三项合起来表示0-255,加一个.表示.,{3}表示重复3次
(2[0-4]\d|25[0-5]|[01]?\d\d?)’) # 0-255
compile(r’’)其中的r表示raw,使用最原始的正则表达式

匹配要不要贪心一点

findall函数,和match、search函数用法相同,但是它会返回一个list,找到在字符串中所有符合模式的字符串
正则表达 - 图12
学习网站:
http://www.cnblogs.com/graphics/archieve/2010/06/02/1749707.html

只匹配双引号中的内容

re_quote = re.compile(r’”(.)”‘)
.
表示任意字符,任意个数,如果加上?代表任意个数但是取尽可能少的情况(并不是所有的双引号包含的情况下取中间个数最少的那个,而是在有多种选择的的情况下,取那种最少字符的那种情况,比如说三个双引号连起来的时候:
“yes.” phone says “no”
如果使用贪心的方法,会变成
“yes.” phone says “no”
如果是加了?,则只会匹配出两个较短的情况:
[‘yes.’, ‘no.’]
)
re_quote = re.compile(r’”(.*?)”‘)

正则匹配可以直接换掉内容吗

可以,使用
regex.sub(str, s)函数,把s中符合regex的部分都替换成str

如何使用分组的序号进行重组和替换

import re
s = ‘替换日期格式:10/01/2008, 12/25/2008’
re_date = re.compile(r’(\d+)/(\d+)/(\d+)’)
re_date.sub(r’\3-\2-\1’, s)
‘替换日期格式:2008-01-10, 2008-25-12’

如何用sub替换掉空格(处理狗屎pdf文件必备)

  • 知识点:\s表示空白字符,+表示1个或多个,\s+表示一个及一个以上的空格(如制表符就是4个空格,通常情况下)
    - 示例代码:
    >import re
    s = ‘ zby 是 天下 第一 大 帅 哥 ! ! ! ! ‘
    re_space = re.compile(r’\s+’)
    re_space.sub(‘’, s)
    ‘zby是天下第一大帅哥!!!!’

案例1:寻找联系方式

知识点

正则表达 - 图13
使用vscode写一段代码
tips:在vscode中直接输入ifm可以直接输出main函数的代码
示例代码:

  1. import re
  2. re_phone = re.compile(r'\d{3}-\d{8}|\d{4}-\d{7}')
  3. def find_phone(s: str)->list:
  4. return re_phone.findall(s)
  5. def main():
  6. s = '010-87595623,0234-5689496,hmm'
  7. print(find_phone(s))
  8. if __name__ == "__main__":
  9. main()

案例:登录验证正则版

正则表达 - 图14

做一个登录验证的一段代码,具备功能:

  • 能验证用户密码是否是以字母开头,长度在8-18位中间,只能包含字母,数字和下划线
    - 能验证用户名是否是汉字

    代码实现

import re
re_phone = re.compile(r'\d{3}-\d{8}|\d{4}-\d{7}')
re_chinese = re.compile(r'^[\u4e00-\u9fa5]{1,8}$')
re_pwd = re.compile(r'[a-zA-Z]\w{7,17}')
def find_phone(s: str)->list:
    '''查找所有手机号,返回列表'''
    return re_phone.findall(s)
def verify_ch(re_obj, text):
    '''判断是否是汉字,是返回True,否则返回False'''
    if re_obj.match(text):
        return True
    else:
        return False
def verify_pwd(re_obj, text):
    '''判断密码是否是字母开头,8-18位仅包含字母数字下划线,是返回True,否则返回False'''
    if re_obj.match(text):
        return True
    else:
        return False
def main():
    user1 = 'zby'
    user2 = '赵博元'
    pwd1 = 'zhao139319'
    pwd2 = '1zhao234'
    print(verify_ch(re_chinese, user1) and '用户名1合格' or '用户名1不合格')
    print(verify_ch(re_chinese, user2) and '用户名2合格' or '用户名2不合格')
    print(verify_pwd(re_pwd, pwd1) and '密码1合格' or '密码1不合格')
    print(verify_pwd(re_pwd, pwd2) and '密码2合格' or '密码2不合格')
if __name__ == "__main__":
    main()

正则表达 - 图15