Python 正则表达式

正则表达式

最简单的正则表达式

In: import re

In: re.match('test', 'test')
Out: <_sre.SRE_Match object; span=(0, 4), match='test'>

In: re.match('test', 'test123')
Out: <_sre.SRE_Match object; span=(0, 4), match='test'>

In: re.match('test', 'tes')
Out: # 无输出

match(pattern, string, flags=0) # re.match 的函数签名, pattern 是模式, string 是要匹配的文本, flags 是标志位, 用于控制正则表达式的匹配方法(比如是否区分大小写, 多行匹配等等)

search() / match() 的区别

In: re.search('test', 'test123')
Out: <_sre.SRE_Match object; span=(0, 4), match='test'>

In: re.search('test', '1test')
Out: <_sre.SRE_Match object; span=(1, 5), match='test'>

In: re.match('test', '1test')
Out: # 无输出

search(pattern, string, flags=0) # re.search 的函数签名

match() 要求从文本开头就匹配, search() 是搜索整个文本, 有匹配项即可。

match() 函数只检测 string 开始位置, 而 search() 会扫描整个 string 查找匹配

也就是说 match() 只有在 0 位置匹配成功的话才有返回, 如果不是开始位置匹配成功的话, match 就返回 none
search() 会扫描整个 string 并返回第一个成功的匹配

元字符

普通字符包括大小写的字母、数字, 而元字符具有特殊的含义, 正是因为元字符, 才使得正则表达式具有非常强的表达能力。

常用的元字符:

.: 圆点符号表示匹配除换行符以外的任意字符

\w: 匹配字母或数字或下划线或汉字

\s: 匹配任意的空白符, 包括空格制表符换页符等

\d: 匹配数字

\b: 匹配单词的开始或结束

^: 匹配字符串的开始

$: 匹配字符串的结束

x|y: 匹配 x 或 y

[xyz]: 字符集合。匹配所包含的任意一个字符

[a-z]: 字符范围。匹配指定范围内的任意字符

In: re.search('..', 'hi') # .
Out: <_sre.SRE_Match object; span=(0, 2), match='hi'>

In: re.search('\w\w\w\w', 'a1_蛤') # \w
Out: <_sre.SRE_Match object; span=(0, 4), match='a1_蛤'>

In: re.search('\s\s\s', ' \r\t') # \s
Out: <_sre.SRE_Match object; span=(0, 3), match=' \r\t'>

In: re.search('\d\d\d', '123') # \d
Out: <_sre.SRE_Match object; span=(0, 3), match='123'>

In: re.search('^test', 'test123') # ^
Out: <_sre.SRE_Match object; span=(0, 4), match='test'>

In: re.search('^test', '123test123') # ^
Out: # 无输出

In: re.search('123$', 'test123') # $
Out: <_sre.SRE_Match object; span=(4, 7), match='123'>

In: re.search('123$', 'test123test') # $
Out: # 无输出

In: re.search('a|b', 'abcd') # x|y
Out: <_sre.SRE_Match object; span=(0, 1), match='a'>

In: re.search('[12b]', 'abcd') # [xyz]
Out: <_sre.SRE_Match object; span=(1, 2), match='b'>

In: re.search('[a-z]', 'qwe') # [a-z]
Out: <_sre.SRE_Match object; span=(0, 1), match='q'>

In: re.search('[d-z]', 'abc') # [a-z]
Out: # 无输出

匹配内容

通过匹配对象的 group() 方法, 可以获得正则表达式匹配的内容

In: match = re.search('\d+', 'hellopg12138world')
In: match.group()
Out: '12138'

重复

一个元字符只能对应匹配一个字符, 如果有重复的匹配项, 我们需要使用下面的方法来处理:

?: 匹配前面的子表达式零次或一次

+: 匹配前面的子表达式一次或多次

*: 匹配前面的子表达式零次或多次

{n}: 重复 n 次

{n, }: 重复 n 次或更多次

{n, m}: 重复 n 到 m 次

In: re.search('ca?t', 'ct') # ?
Out: <_sre.SRE_Match object; span=(0, 2), match='ct'>

In: re.search('ca?t', 'cat') # ?
Out: <_sre.SRE_Match object; span=(0, 3), match='cat'>

In: re.search('ca?t', 'caat') # ?
Out: # 无输出

In: re.search('ca+t', 'ct') # +
Out: 无输出

In: re.search('ca+t', 'cat') # +
Out: <_sre.SRE_Match object; span=(0, 3), match='cat'>

In: re.search('ca+t', 'caaaaaat') # +
Out: <_sre.SRE_Match object; span=(0, 8), match='caaaaaat'>

In: re.search('ca*t', 'cat') # *
Out: <_sre.SRE_Match object; span=(0, 3), match='cat'>

In: re.search('ca*t', 'cart') # *
Out: # 无输出

In: re.search('ca*t', 'caaaat') # *
Out: <_sre.SRE_Match object; span=(0, 6), match='caaaat'>

In: re.search('\d{5}', '123456') # {n}
Out: <_sre.SRE_Match object; span=(0, 5), match='12345'>

反义

[^x]: 匹配除了 x 以外的任意字符

[^abc]: 匹配除了 abc 这几个字符以外的任意字符

\W: 匹配任意不是数字, 字母, 下划线, 汉字的字符, 等价于 [^A-Za-z0-9_]

\S: 匹配任意不是空白符的字符, 等价于 [^ \f\n\r\t\v]

\D: 匹配任意非数字的字符 等价于 [^0-9]

\B: 匹配不是单词开头或结束的位置

贪婪与懒惰

当正则表达式中包含能接受重复的限定符时, 通常的行为是匹配尽可能多的字符, 这被称为贪婪匹配。
有时我们需求是匹配尽可能少的匹配项, 这时需要懒惰匹配模式。

In: re.search('a.*b', 'aabacdabebb').group() # 贪婪匹配
Out: 'aabacdabebb' # 匹配最长的以 a 开始, 以 b 结束的字符串

In: re.search('a.?b', 'aabacdabebb').group() # 懒惰匹配
Out: 'aab' #

懒惰限定符:

*?: 重复任意次, 但尽可能少重复

+?: 重复 1 次或更多次, 但尽可能少重复

??: 重复 0 次或 1 次, 但尽可能少重复

{n, m}?: 重复 n 到 m 次, 但尽可能少重复

{n, }?: 重复 n 次以上, 但尽可能少重复

编译标志

编译标志可以修改正则表达式的一些运行方式

DOTALL, S: 使 . 匹配包括行在内的所有字符

IGNORECASE, I: 使匹配对大小写不敏感

LOCALE, L: 做本地化识别匹配

MULTILINE, M: 多行匹配, 影响 ^ 和 $

VERBOSE, X: 详细装填

DEBUG: 调试模式

In: re.search('.', '\n')
Out: # 无输出

In: re.search('.', '\n', re.S)
Out: <_sre.SRE_Match object; span=(0, 1), match='\n'>

In: re.search('a.', 'A\n', re.S|re.I)
Out: <_sre.SRE_Match object; span=(0, 2), match='A\n'>

编译正则表达式

search() 和 match() 方法在背后做了两件事情:

1.编译正则表达式, 若正则表达式的字符串本身不合法, 则报错。

2.用编译后的正则表达式去匹配字符串。对于程序频繁使用的表达式要做预编译, 在预编译之后, 重复使用它时就不再需要编译

In: regex = re.compile(r'^\d{1,3}$')
In: regex.match('12')
Out: <_sre.SRE_Match object; span=(0, 2), match='12'>

In: regex.match('1234')
Out: # 无输出

检索和替换

re.sub(pattern, repl, string, count=0, flags=0) # re.sub 签名
# 第一个参数是模式
# 第二个参数是要替换成的内容
# 第三个是待匹配的文本
# 如果有多项匹配的内容, 可以通过第四个参数 count 指定匹配的数量。
# flags 是编译的标志
In: re.sub('\d+', '', 'test123')
Out: 'test'

In: re.sub('\d', '', 'test123')
Out: 'test'

In: re.sub('\d', '', 'test123', count=2)
Out: 'test3'

findall()/finditer()

findall() 和 finditer() 是用来搜索文本, 返回全部能匹配的字符串或者对象的方法。

findall() 是一次性地把结果放到列表中返回

finditer() 返回一个可以顺序访问每一个匹配对象的迭代器

In: re.findall('\d', '1a2b3c4d')
Out: ['1', '2', '3', '4']

In: for i in re.finditer('\d', '1a2b3c4d'):
...     print(i)
...
Out:
<_sre.SRE_Match object; span=(0, 1), match='1'>
<_sre.SRE_Match object; span=(2, 3), match='2'>
<_sre.SRE_Match object; span=(4, 5), match='3'>
<_sre.SRE_Match object; span=(6, 7), match='4'>

分组

很多需求里面, 一个表达式会同时匹配多个模式, 我们需要把他们分组, 分组是通过 () 来标识的

() 也是元字符, () 内的表达式成为一组。

通过给匹配对象的 group() 传入分组位置, 就可以获得对应分组的匹配内容。

位置是从 1 开始的, group() 可以一次性传入多个分组位置, 返回的是 tuple()。

使用 groups() 方法可以得到匹配对象的所有分组。

In: m = re.match('(a)b', 'ab')
In: m.group(1)
Out: 'a'

In: m = re.match('([a-c]+).*(\w)', 'abcbde')
In: m.groups()
Out: ('abcb', 'e')

In: m.group(1), m.group(2), m.group(1, 2)
Out: ('abcb', 'e', ('abcb', 'e'))

命名分组

命名分组是给具有默认分组编号的组另外取一个别名

(?P<name>regex) # 命名分组格式
In: pattern = '(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
In: m = re.match(pattern, '1998-09-23')
In: m.groupdict() # 通过 groupdict() 可以得到命名分组的名字和结果
Out: {'year': '1998', 'month': '09', 'day': '23'}

In: m.group('year')
Out: '1998'

In: m.group('month')
Out: '09'

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

推荐阅读更多精彩内容

  • #首先,python中的正则表达式大致分为以下几部分: 元字符 模式 函数 re 内置对象用法 分组用法 环视用法...
    mapuboy阅读 1,589评论 0 51
  • re模块手册 本模块提供了和Perl里的正则表达式类似的功能,不关是正则表达式本身还是被搜索的字符串,都可以...
    喜欢吃栗子阅读 3,970评论 0 13
  • 前言: 什么是正则表达式? 正则表达式(Regular expressions 也称为 REs,或 regexes...
    小喜_ww阅读 3,674评论 3 7
  • 正则表达式 1. 正则表达式概述 正则表达式,又称正规表示式、正规表示法、正规表达式、规则表达式、常规表示法(英语...
    PythonMaO阅读 1,261评论 0 1
  • 概述 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。 Python 自1....
    MiracleJQ阅读 384评论 0 0