夜间模式暗黑模式
字体
阴影
滤镜
圆角
主题色
Python学习笔记12-正则表达式

这里看的书是 Python核心编程(第三版)中文版 , 因为 Python基础教程(第三版) 后面的数据库, 网络和web都讲得比较粗略

B2-P1: B2表示是Python核心编程, 没有标注书名的默认为Python基础教程

正则表达式

常见的正则表达式符号和特殊字符(B2-P5)

表示法 描述 实例 详解
符号
literal 文本串字面值 foo
re1|re1 匹配正则表达式re1re2 foo|bar
. 句点, 匹配任何字符(\n除外) b.b
^ 匹配字符串起始 ^Dear
$ 匹配字符串终止 /bin/*sh$
* 匹配 0 次或者多次前面出现的正则表达式 [A-Za-z0-9]*
+ 匹配 1 次或者多次前面出现的正则表达式 [a-z]+\.com
? 匹配 0 次或者 1 次前面出现的正则表达式 goo?
{N} 匹配 N 次前面出现的正则表达式 [0-9]{3}
{M,N} 匹配 M~N 次前面出现的正则表达式 [0-9]{5,9} 逗号后面不能有空格
[...] 匹配来自字符集的任意单一字符 [aeiou]
[..x−y..] 匹配x-y范围中的任意单一字符 [0-9],[A-Za-z]
[^…] 不匹配此字符集中出现的任何一个字符, 包括某一范围的字符(如果在此字符集中出现) [^aeiou],[^A-Za-z0-9]
(*|+|?|{})? 用于匹配上面频繁出现/重复出现符号的非贪婪版本(*, +, ?, {}) .*?[a-z]
(…) 匹配封闭的正则表达式, 然后另存为子组 ([0-9]{3})?,f(oo|u)bar 子组编号: 整体作为编号0, 其它根据左括号出现的次序编号为1, 2, …
特殊字符
\d 匹配任何十进制数字, 与[0-9]一致(\D\d相反, 不匹配任何非数值型的数字) data\d+.txt
\w 匹配任何字母数字字符, 与[A-Za-z0-9_]相同(\W与之相反 [A-Za-z_]\w+
\s 匹配任何空格字符, 与[\n\t\r\v\f]相同(\S与之相反) of\sthe
\b 匹配任何单词边界(\B与之相反) \bThe\b
\N 匹配已保存的子组N(参见上面的(…) price:\16
\c 逐字匹配任何特殊字符c(即, 仅按照字面意义匹配, 不匹配特殊含义) \., \\, \*
\A(\Z) 匹配字符串的起始(结束)(另见上面介绍的^$) \ADear
扩展表示法
(?iLmsux) 在正则表达式中嵌入一个或者多个特殊"标记"参数(或者通过函数/方法) (?x), (?im)
(?:…) 表示一个匹配不用保存的分组 (?:\w+\.)* 子组编号将会跳过这个分组, 例如'(?:a)(b)’, (b)为子组1
(?P<name>…) 像一个仅由name标识而不是数字ID标识的正则分组匹配 (?P<data>)
(?P<data>)(?P=name) 在同一字符串中匹配由(?P<name)分组的之前文本 (?P=data)
(?#…) 表示注释, 所有内容都被忽略 (?#comment)
(?=…) 匹配条件是如果…出现在之后的位置, 而不使用输入字符串; 称作正向前视断言 (?=.com)
(?!…) 匹配条件是如果…不出现在之后的位置, 而不使用输入字符串; 称作负向前视断言 (?!.net)
(?<=…) 匹配条件是如果…出现在之前的位置, 而不使用输入字符串; 称作正向后视断言 (?<=800-)
(?<!…) 匹配条件是如果…不出现在之前的位置, 而不使用输入字符串; 称作负向后视断言 (?<!192\.168\.)
(?(id/name)Y|N) 如果分组所提供的id或者name(名称)存在, 就返回正则表达式的条件匹配Y, 如果不存在, 就返回N; N是可选项 (?(1)y|x)

核心函数和方法(B2-P12)

函数/方法 描 述
仅仅是 re 模块函数
compile(pattern, flags = 0) 使用任何可选的标记来编译正则表达式的模式, 然后返回一个正则表达式对象
re 模块函数和正则表达式对象的方法
match(pattern, string, flags=0) 尝试使用带有可选的标记的正则表达式的模式来匹配字符串。如果匹配成功, 就返回匹配对象; 如果失败, 就返回None
search(pattern, string, flags=0) 使用可选标记搜索字符串中第一次出现的正则表达式模式。如果匹配成功, 则返回匹配对象; 如果失败, 则返回None
findall(pattern, string [, flags]) 查找字符串中所有(非重复)出现的正则表达式模式, 并返回一个匹配列表
finditer(pattern, string [, flags] ) findall()函数相同, 但返回的不是一个列表, 而是一个迭代器。对于每一次匹配, 迭 代器都返回一个匹配对象
split(pattern, string, max=0) 根据正则表达式的模式分隔符, split函数将字符串分割为列表, 然后返回成功匹配的列表, 分隔最多操作 max次(默认分割所有匹配成功的位置)
re 模块函数和正则表达式对象方法
sub(pattern, repl, string, count=0) 使用repl替换所有正则表达式的模式在字符串中出现的位置, 除非定义count, 否则就 将替换所有出现的位置(另见subn()函数, 该函数返回替换操作的数目)
purge() 清除隐式编译的正则表达式模式
常用的匹配对象方法(查看文档以获取更多信息)
group(num=0) 返回整个匹配对象, 或者编号为num的特定子组
groups(default=None) 返回一个包含所有匹配子组的元组(如果没有成功匹配, 则返回一个空元组)
groupdict(default=None) 返回一个包含所有匹配的命名子组的字典, 所有的子组名称作为字典的键(如果没有成功匹配, 则返回一个空字典)
常用的模块属性(用于大多数正则表达式函数的标记)
re.I、re.IGNORECASE 不区分大小写的匹配
re.L、re.LOCALE 根据所使用的本地语言环境通过\w、\W、\b、\B、\s、\S实现匹配
re.M、re.MULTILINE ^和$分别匹配目标字符串中行的起始和结尾, 而不是严格匹配整个字符串本身的起始和结尾
re.S、re.DOTALL "."(点号)通常匹配除了\n(换行符)之外的所有单个字符; 该标记表示"."(点号) 能够匹配全部字符
re.X、re.VERBOSE 除非通过反斜线转义, 否则所有空格加上#(以及在该行中所有后续文字)都被忽略, 在一个字符类中或者允许注释并且提高可读性

match和search

其中searchmatch返回一个MatchObject对象, 包含了与模式匹配的子串的信息, 还包括模式的各部分与子串的那一部分匹配的信息

  • MatchObject对象的一些重要方法:

    方法 描述
    group([group1, …]) 获取与给定子模式(编组)匹配的子串
    start([group]) 返回与给定编组匹配的子串的起始位置
    end([group]) 返回与给定编组匹配的子串的终止位置(与切片一样,不包含终止位置)
    span([group]) 返回与给定编组匹配的子串的起始和终止位置

findall

这一部分中文书翻译的跟狗shi一样, 直接去看python的文档一下就懂了

感受一下中文翻译, 我怀疑是机翻:

子组在一个更复杂的返回列表中搜索结果,而且这样做是有意义的,因为子组是允许从 单个正则表达式中抽取特定模式的一种机制,例如匹配一个完整电话号码中的一部分(例如 区号),或者完整电子邮件地址的一部分(例如登录名称)。 对于一个成功的匹配,每个子组匹配是由 findall()返回的结果列表中的单一元素;对于 多个成功的匹配,每个子组匹配是返回的一个元组中的单一元素,而且每个元组(每个元组 都对应一个成功的匹配)是结果列表中的元素。这部分内容可能第一次听起来令人迷惑,但 是如果你尝试练习过一些不同的示例,就将澄清很多知识点。

findall返回一个列表, 包含所有不重叠的所有匹配, 如果模式含有多个子组, 则每个匹配用一个元组表示, 元组包含匹配的每个子组匹配的串)

# 注意''和'ow', 之所以不是''和'how'是因为''和'how'有重叠(字符串开头)
>>> re.findall(r'^|\w+', 'how are you')
['', 'ow', 'are', 'you']

flags标记

flags标记值可以为模块属性(re.I, re.L....)或它们之间相与(re.I|re.L表示不区分大小写及根据本地语言), 也可以在字符串中使用(?iLmsux)表示((?iL)与在函数实参中flags = re.I|re.L等价)

sub替换

sub()返回替换后的字符串, subn()返回由替换后的字符串和替换次数元组

>>> re.sub('[ab]', 'X', 'abcdefab')
'XXcdefXX'
>>> re.subn('[ab]', 'X', 'abcdefab')
('XXcdefXX', 4)

repl参数中可以使用\子组号来表示子组, 但是要注意\的转义

>>> re.sub('([ab])([cd])', r'\2\1', 'acbd')
'cadb'
>>> re.sub('([ab])([cd])', '\\2\\1', 'acbd')
'cadb'

扩展符号(B2-P24)

给子组命名

使用符号(?P<name>)给一个子组命名, 然后可以在sub函数中使用\g<name>来表示它们(等价与原来的\子组编号, 注意即使使用了这种方法给子组命名, 依旧可以使用原来的数字编号使用它们

使用(?P<name>)给子组命名后, 可以在当前正则表达式后面使用符号(?P=name)来重复这个子组

  • 注意之后出现的子组必须和之前匹配的一模一样, 也就是说如果(?P<num>\d{3})匹配了’123′, 那么之后出现的(?P=num)只能匹配’123’而不能匹配其它的三个数字的情况
>>> re.sub('(?P<re1>[ab])(?P<re2>[cd])(x)', r'\g<re2>\g<re1>\1', 'acxbd')
'caabd'

>>> re.findall(r'(?P<number>\d{3})-(?P=number)', '123-123-456-789-789')
['123', '789']

注释

使用符号(?#...)表示注释

前视断言和后视断言

这里的’前’指的是匹配完成后的匹配串后面的位置(lookahead), ‘后’指的是匹配串之前的位置(lookbehind)

前视断言: (?=re1)表示只有当模式re1能在之后得到匹配, 整个模式匹配, re1不会捕获任何字符(只是’看’), 例如ab(?=cd)会匹配’abcd'(匹配结果是ab), 而不会匹配’abab’

前视否定断言: (?!re1)与前视断言相仿, 只有当re1在之后不能得到匹配整个模式串才会匹配

后视断言: (?<=re1)只有re1在之前得到匹配整个模式串才匹配, 例如(?<=ab)cd只会匹配’abcd’, 而不会匹配’xycd’

后视否定断言: (?<!re1)同上

判断指定子组是否存在

(?(id/name) yes-pattern | no-parttern): 当名为name或者编号为id的子组存在时候, 使用yes-pattern匹配, 否则使用no-parttern匹配, no-pattern是可选的

例如: (<)?(\w+@\w+(?:\.\w+))(?(1)>|$)可以同时匹配'<user@host.com>''user@host.com', 最后一个判断条件表示只有当子组1也就是<存在时匹配>, 否则匹配字符串结束$

贪婪与非贪婪

+, *, ?, {}后面加上?表示非贪婪模式

贪婪指的是每次匹配尽可能匹配更长, 而非贪婪每次尽可能匹配地更短, 例如对于字符串’abcdefg’, ab.{1,3}匹配结果是’abcde’, 而ab.{1,3}?匹配结果是abc

暂无评论

发送评论


				
上一篇
下一篇