一直对正则表达式一知半解,终于狠下心来啃了啃,把笔记记录一下~

正则表达式在不同语言中的应用有细微的差别,这里以python为例。

正则表达式在不同语言中的差别,请参考:

https://deerchao.cn/tutorials/regex/diffs.html

1 python中使用正则表达式

python中通过re模块使用正则表达式。首先导入re模块:

import re

1.1 re.match

re.match(pattern, string, flags=0)

re.match只匹配开头,成功返回一个匹配的对象,失败返回none。

例:

print re.match(r'\d+', '12twothree34four').group()

此处介绍一下返回的对象可以执行的方法:

group([group1, …]) 方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() 或 group(0);

start([group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;

end([group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;

span([group]) 方法返回 (start(group), end(group))。

1.2 re.search

re.search(pattern, string, flags=0)

re.search匹配整个字符串,成功返回一个匹配的对象,失败返回none。

例:

print re.search(r'\d+', '12twothree34four').group()

match和search都是只返回一个,想拿到匹配的所有子串,要用findall或者finditer。

1.3 re.compile

re.compile(pattern[, flags])

re.compile编译生成一个正则表达式对象供其他方法使用。

例:

pattern = re.compile(r'\d+')
print pattern.match('one12twothree34four', 3, 10).group()

后面的3、10从第3位开始匹配到第10位截止,省略的话和re.match一样默认从头匹配。

pattern.search()同理。

pattern.findall()

findall将匹配的所有子串以列表的形式返回。

例:

pattern = re.compile(r'\d+')
print pattern.findall('one12twothree34four')

此处注意,match和search返回的都是对象,所以要再用group()方法取到字符串,而findall直接返回的是字符串的列表。

1.4 re.finditer

将匹配的所有子串以迭代器的形式返回。

例:

it = re.finditer(r'\d+', '12twothree34four')
for match in it:
    print match.group()

注意,通过finditer返回的迭代器获得的是对象不是字符串,这点和findall不一样。

关于处理选项(flags):

flags含义
re.I(这是大写i)大小写不敏感
re.Llocale-aware,本地化识别,表示特殊字符集 w, W, b, B, s, S 依赖于当前环境
不常用
re.M多行匹配
re.S使.可以匹配所有字符,包括换行符
re.U根据unicode字符集解析字符,表示特殊字符集依赖于unicode库
不常用
re.X忽略模式里的空白符

参考:

https://www.runoob.com/python/python-reg-expressions.html

python中正则表达式的b的处理

python中正则表达式使用b,或者其他包含反斜杠的元字符,需要在表达式字符串前加r,表示非转义的原始字符串,这样在表达式里就可以正常使用反斜杠了。

2 正则表达式的基本语法

2.1 符号对照表

符号含义
.匹配除了换行符外的任意字符
*前边的内容连续重复匹配任意次,以使整个表达式得到匹配
+前边的内容连续重复匹配大于等于一次
?前边的内容连续重复匹配小于等于一次
(用在限定符后面表示变为懒惰模式)
{n}前边的内容连续重复匹配n次
{n,m}前边的内容连续重复匹配n到m次
{n,}前边的内容连续重复匹配n次以上
w匹配一位字母、数字、下划线、汉字等
d匹配一位数字
s匹配任意空白符,如空格、制表符、换行符等
b匹配单词的开头或结尾
^匹配字符串的开头
$匹配字符串的结尾
(如果指明处理多行,则^和$分别匹配行的开头和结尾)
[abc]匹配自定义的字符集合,可以用连字符指定范围,如[0-9],[a-z0-9A-Z]
(这里的字符不需要转义)
|这个符号用来隔开不同的规则,如a|b,ab两个分支条件,满足a或b都可以匹配,如果已满足a,不再考虑b
()以上限定符都是指重复单个字符,如果想重复多个字符,要用括号括起来,然后后面加限定符
W表示w的反义,也就是匹配一位不是字母、数字、下划线、汉字的任意字符。还有比如s、d、b等元字符,小写变大写也都是表示反义
D匹配一位不是数字的任意字符
S匹配一位不是空白符的任意字符
B匹配不是单词开头或结尾的位置
[^abc]^符号用在这里表示集合的反义,也就是匹配集合中字符abc以外的任意字符
n后向引用。匹配第n个子表达式已匹配的内容
子表达式指用小括号括起来的表达式,n是一个数字,比如1,2,分别指第一个和第二个子表达式匹配的内容。
("n"其实表示的是换行符)
k<name>后向引用。有时候用1、2来表达比较混乱,所以需要给子表达式自定义一个名字,这时候再用k来引用。具体用法是:
比如,给表达式(exp)指定名字,(?<name>exp);
引用的时候,k<name>;
也可以把尖括号换成单引号'',如(?'name'exp),k'name'
?<name>用在小括号里,给子表达式指定名字,用于后向引用。具体用法见上一条
(?:exp)这个表达式不捕获匹配到的内容exp,也就不给捕获内容分配编号(编号指的就是1、2里的数字,后向引用的时候用到)。可以理解为,匹配符合这个表达式的位置,它是为了给整个表达式定位而存在的
(?=exp)匹配exp前面的位置。这个表达式和下面的几个类似于^、$、b这样,匹配一个位置,也被称为零宽断言。这个表达式叫零宽度正预测先行断言
比如,bw+(?=ingb),匹配以ing结尾的单词,不包含ing,如果处理字符串"This thing is very exciting"则匹配到"excit"
(?<=exp)匹配exp后面的位置,称作零宽度正回顾后发断言
(?!exp)匹配非exp前面的位置,也就是说这个位置后面跟的不能是exp
因为表否定意义,所以也叫负向零宽断言。这个表达式叫零宽度负预测先行断言
(?<!exp)匹配非exp后面的位置,也就是说这个位置前面的不能是exp,称作零宽度负回顾后发断言
(?#comment)正则表达式的注释

还有其他没有提到的语法,参考官方文档:

https://docs.python.org/zh-cn/3/library/re.html

元字符的匹配
要匹配元字符本身,使用转义符号,如:
\.
\*
\\

正则表达式添加注释
使用(?#comment),也可以启用“忽略模式里的空白符”选项,就可以这样写注释:

(?<=    # 断言要匹配的文本的前缀
<(\w+)> # 查找尖括号括起来的内容
        # (即HTML/XML标签)
)       # 前缀结束
.*      # 匹配任意文本
(?=     # 断言要匹配的文本的后缀
<\/\1>  # 查找尖括号括起来的内容
        # 查找尖括号括起来的内容
)       # 后缀结束

在#后面的内容在使用时都会被当作注释忽略掉。

贪婪与懒惰
通常情况下,限定符是贪婪的,也就是说,在使整个表达式能得到匹配的前提下,匹配尽可能多的字符。
而懒惰是指,在使整个表达式能得到匹配的前提下,匹配尽可能少的字符。在限定符后面加上?可以是贪婪模式变为懒惰模式。比如,a.*b是贪婪的,用来匹配字符串aaabaabab会匹配到aaabaabab,加上?变成a.*?b,就是懒惰的了,匹配尽可能少的字符,会匹配到aaabaabab

参考:

https://deerchao.cn/tutorials/regex/regex.htm

还有一些有待了解:

python正则表达式实现平衡组

python正则表达式递归匹配

文章目录