Python:正则表达式

1. 什么是正则表达式

正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配

正则表达式是对字符串操作的一种逻辑公式,用事先定义好的一些特殊字符,以及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑

2. 字符串匹配方法

2.1 re.match()

re.match():尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回None

import re
str = "张三李四王五赵六李四"

# match():只从开头匹配,不成功直接返回None
result = re.match("李四",str)
print(result) #None

2.2 re.search()

re.search():扫描整个字符串并返回第一个成功的匹配

import re
str = "张三李四王五赵六李四"

# search():匹配的是整个字符串
result = re.search("李四",str)
print(result) #<re.Match object; span=(2, 4), match='李四'>
# span():返回匹配字符串所在位置
print(result.span()) #(2, 4)
# group():返回匹配内容
print(result.group()) #李四
# groups():返回一个包含所有小组字符串的元组,从1到所含的小组号
print(result.groups()) #()

2.3 re.findall()

re.findall():返回所有成功的匹配字符串

import re

str = "张三李四王五赵六李四"
# findall():返回所有匹配的字符串
result = re.findall("李四",str)
print(result) #['李四', '李四']

3. 替换和分割

3.1 re.sub()

re.sub(pattern, repl, string, count=0, flags=0)

  • pattern: 正则中的模式字符串
  • repl: 替换的字符串,也可为一个函数
  • string: 要被查找替换的原始字符串
  • count: 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配
import re
 
phone = "2004-959-559 # 这是一个国外电话号码"
 
# 删除字符串中的 Python注释 
num = re.sub(r'#.*$', "", phone)
print("电话号码是: ", num)
 
# 删除非数字(-)的字符串 
num = re.sub(r'\D', "", phone)
print("电话号码是 : ", num)

3.2 re.split()

re.split(pattern, string[, maxsplit=0, flags=0])

  • pattern:匹配的正则表达式
  • string:要匹配的字符串
  • maxsplit: 分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数
  • flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等
>>>import re
>>> re.split('\W+', 'runoob, runoob, runoob.')
['runoob', 'runoob', 'runoob', '']
>>> re.split('(\W+)', ' runoob, runoob, runoob.') 
['', ' ', 'runoob', ', ', 'runoob', ', ', 'runoob', '.', '']
>>> re.split('\W+', ' runoob, runoob, runoob.', 1) 
['', 'runoob, runoob, runoob.']

4. 正则符号

4.1 第一类符号

  1. [ ]

    • 用于表示一组字符,如果^是第一个字符,则表示的是一个补集
    • 如[0123]、[zxcv]、[‘@#¥]表示的是有限个字符
    • [0-9]、[a-z]表示的是字符集
    • [^0-9]表示的事除了数字外的字符
    import re
    
    s = "afo3oir45oij890aouih"
    result1 = re.findall("[1234][3456]",s)
    result2 = re.findall("[a-z][0-3][a-z]",s)
    result3 = re.findall("[^a-z][0-9][^a-z]",s)
    print(result1) #['45']
    print(result2) #['o3o']
    print(result3) #['890']
    
  2. |

    • a|b,表示匹配a或者b
  3. ()

    • (word1|word2|word3),表示要么是word1,要么是word2,要么是word3
    • 一个()代表是一组,按照出现次序从1排列,若想调用分组排序,可用group(数字)
    • ?P<名字>可以给分组定义自己的名字
    import re
    
    email = "1123971628@qq.com"
    result = re.match(r"\w{5,20}@(163|126|qq)\.(com|cn)",email)
    print(result) #<re.Match object; span=(0, 17), match='1123971628@qq.com'>
    

4.2 第二类符号

  1. *、+、?

    • "*"用于将前面的模式匹配0次或多次,>=0
    • "+"用于将前面的模式匹配1次或多次,>=1
    • "?"用于将前面的模式匹配0次或1次,0或1
    import re
    
    s = "afo3oir45oij890aouih"
    result2 = re.findall("[a-z][0-9]*[a-z]",s)
    print(result2) #['af', 'o3o', 'ir', 'oi', 'j890a', 'ou', 'ih']
    result2 = re.findall("[a-z][0-9]+[a-z]",s)
    print(result2) #['o3o', 'r45o', 'j890a']
    result2 = re.findall("[a-z][0-9]?[a-z]",s)
    print(result2) #['af', 'o3o', 'ir', 'oi', 'ao', 'ui']
    
  2. {m}、{m,}、{m,n}

    • "{m}"用于验证将前面的模式匹配m次
    • "{m,}"用于验证将前面的模式匹配m次或者多次
    • "{m,n}"用于验证将前面的模式匹配大于等于m次并且小于等于n次
    import re
    
    # 验证是否为qq号码
    s = "1123971638"
    result = re.findall("[1-9][0-9]{5,11}",s)
    print(result) #['1123971638']
    result = re.findall("[1-9][0-9]{5}",s)
    print(result) #['112397']
    result = re.findall("[1-9][0-9]{5,}",s)
    print(result) #['1123971638']
    

4.3 第三类符号

  1. .、^、$

    • "."用于匹配除换行符(\n)之外的所有字符,如果想要表示".",则可使用"."表示
    • "^"用于匹配字符串的开始,即行首,匹配时从头开始匹配
    • "$"用于匹配字符串的末尾,即行尾,一直匹配到结尾,如果末尾有\n,就匹配\n前面的那个字符
    import re
    
    # 验证是否为qq号码
    s = "1123971628386045673"
    result = re.findall("[1-9][0-9]{4,10}",s)
    print(result) #['1123971638']
    result = re.findall("^[1-9][0-9]{4,10}$",s)
    print(result) #[]
    
    s = "1123971628"
    result = re.findall("^[1-9][0-9]{4,10}$",s)
    print(result) #['1123971628']
    

4.4 第四类符号

  1. \A、\Z、\b、\B、\d、\D、\S、\w、\W
    • \A:表示从字符串的开始处匹配
    • \Z:表示从字符串的结束处匹配,如果存在换行,只匹配到换行前的结束字符串。
    • \b:匹配一个单词边界,也就是指单词和空格间的位置。例如,’py\b’可以匹配"python"中的'py'文件,但不能匹配"openpyx1"中的’py'
    • \B:匹配非单词边界。’py\b’可以匹配"openpyx1"中的’py',但不能匹配"python”中的’py'文件
    • \d:匹配任意数字,等价于[0-9]
    • \D:匹配任意非数字字符,等价于["\d]
    • \s:匹配任意空白字符,等价于[\t\n\r\f]
    • \S:匹配任意非空白字符,等价于[~\s]
    • \w:匹配任意字母数字及下划线,等价于[a-zA-Z0-9]
    • \W:匹配任意非字母数字及下划线,等价于[\w]
    • \:匹配原义的反斜杠\

5. 贪婪匹配与惰性匹配

Python里数量词默认是贪婪的(在少数语言中也可能是默认非贪婪),总是尝试匹配尽可能多的字符

非贪婪则相反,总是尝试匹配尽可能少的字符

在"*"、"?"、"+"、"{m,n}"后面加上"?",使贪婪变成非贪婪

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352