在做NLP的语言预处理时需要用到许多正则表达式,因此在这做一个笔记,方便用时查阅
如果用的时 PyCharm 这里有一个快速查阅 re 的方法
(CTRL+F/R)使用查找功能时 点击Regex 就能弹出一个正则表达式的摘要 便于快速查阅 内容相对丰富
RE 方法简介
先简单介绍下 re 模块的使用使用方法:
import re
** re.match(pattern, string, flags=0)**
从左至右匹配
pattern: 匹配的正则表达式
string: 要匹配的字符串
flags: 标志位,用于控制匹配方式
成功返回匹配 MatchObject 对象,否则返回None
MatchObject 属性
string 匹配时使用的文本
re 匹配时使用的Pattern对象。
pos 文本中正则表达式开始搜索的索引
lastindex 最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为None
lastgroup: 最后一个被捕获的分组的别名。如果这个分组没有别名或者没有被捕获的分组,将为None。
MatchObject 方法
group() 返回被 RE 匹配的字符串 获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回
groups([default]) 以元组形式返回全部分组截获的字符串 相当于调用group(1,2,…)default表示没有截获字符串的组以这个值替代,默认为None。
groupdict([default])返回以有别名的组的别名为键、以该组截获的子串为值的字典,没有别名的组不包含在内。default含义同上
start(group) 返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。group默认值为0。
end(group) 返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引+1)。group默认值为0。
span(group) 返回一个元组包含匹配 (开始,结束) 的位置 (start(group), end(group))。
match = re.match(r'(\w+) (\w+)(?P<sign>.*)', 'hello world!')
print(match.string) # hello world!
print(match.re) # re.compile('(\\w+) (\\w+)(?P<sign>.*)')
print(match.pos) # 0
print(match.lastindex) # 3
print(match.lastgroup) # sign
print(match.group(0, 1)) # ('hello world!', 'hello')
print(match.groups()) # ('hello', 'world', '!')
print(match.groupdict()) # {'sign': '!'}
print(match.start(1)) # 0
print(match.end(1)) # 5
print(match.span(1)) # (0, 5)
re.sub(pattern, repl, string, count):
使用repl替换string中每一个匹配的子串后返回替换后的字符串。
当repl是一个字符串时,可以使用\id或\g、\g引用分组,但不能使用编号0。
当repl是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
count用于指定最多替换次数,不指定时全部替换。
re.sub(pattern, repl, string, count):
返回 (sub(repl, string, count), 替换次数)。
# 当repl是一个字符串时
print(re.sub(r'\([^)]*\)', ',', '(南)(京)(长江)大桥', 2)) # ,,(长江)大桥
# 当repl是一个方法时
# 将匹配的数字乘以 2
def double(matched):
value = int(matched.group('value'))
return str(value * 2)
s = 'A23G4HFD567'
print(re.sub(r'(?P<value>\d+)', double, s)) # A46G8HFD1134
print(re.subn(r'\([^)]*\)', ',', '(南)(京)(长江)大桥', 2)) # (',,(长江)大桥', 2)
re.split(pattern, string, maxsplit=0, flags=0)
按照能够匹配的子串将字符串分割后返回列表
pattern: 匹配的正则表达式
string: 要匹配的字符串
flags: 标志位,用于控制匹配方式
maxsplit 分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。
成功返回匹配 objec 对象,否则返回None
split = re.split(r'\W', '南京,长江,大桥。')
print(split) # ['南京', '长江', '大桥', '']
split = re.split(r'(\W+)', '南京,长江,大桥。')
print(split) # ['南京', ',', '长江', ',', '大桥', '。', '']
split = re.split(r'(\W+)', '南京,长江,大桥。', 1)
print(split) # ['南京', ',', '长江,大桥。']
Pattern
Pattern对象是一个编译好的正则表达式,通过Pattern提供的一系列方法可以对文本进行匹配查找。
Pattern不能直接实例化,必须使用re.compile()进行构造。
pattern: 匹配的正则表达式
flags: 编译时用的匹配模式。数字形式。
groups: 表达式中分组的数量。
groupindex: 以表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。
p = re.compile(r'(\w+) (\w+)(?P<sign>.*)', re.DOTALL)
print("p.pattern:", p.pattern) # p.pattern: (\w+) (\w+)(?P<sign>.*)
print("p.flags:", p.flags) # 48
print("p.groups:", p.groups) # 3
print("p.groupindex:", p.groupindex) # {'sign': 3}
re.search(pattern, string, flags)
这个方法用于查找字符串中可以匹配成功的子串。从string的pos下标处起尝试匹配pattern,
如果pattern结束时仍可匹配,则返回一个Match对象;若无法匹配,则将pos加1后重新尝试匹配;直到pos=endpos时仍无法匹配则返回None。
pos和endpos的默认值分别为0和len(string));re.search()无法指定这两个参数,参数flags用于编译pattern时指定匹配模式。
search = re.search(r'world', 'hello world!')
print(search.group()) # world
re.findall(pattern, string, flags)
搜索string,以列表形式返回全部能匹配的子串。
print(re.findall(r'\([^)]*\)', '(南)(京)(长江)大桥')) # ['(南)', '(京)', '(长江)']
re.finditer(pattern, string, flags):
搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。
[print(w.group()) for w in re.finditer(r'\([^)]*\)', '(南)(京)(长江)大桥')] # (南) (京) (长江)
分组匹配
s = '1102231990xxxxxxxx'
res = re.search(r'(?P<province>\d{3})(?P<city>\d{3})(?P<born_year>\d{4})',s)
print(res.groupdict()) # {'province': '110', 'city': '223', 'born_year': '1990'}
贪婪/非贪婪匹配
*、+限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个?就可以实现非贪婪或最小匹配。
例如,您可能搜索 HTML 文档,以查找括在 H1 标记内的章节标题。该文本在您的文档中如下:
<H1>Chapter 1 - 介绍正则表达式</H1>
贪婪:下面的表达式匹配从开始小于符号 (<) 到关闭 H1 标记的大于符号 (>) 之间的所有内容。
/<.*>/
非贪婪:如果您只需要匹配开始和结束 H1 标签,下面的非贪婪表达式只匹配 <H1>
。
/<.*?>/
通过在 *、+ 或 ? 限定符之后放置 ?,该表达式从"贪婪"表达式转换为"非贪婪"表达式或者最小匹配。
正则表达式修饰符 - 可选标志
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
large = re.match(r'HELLO', 'hello world!', re.I)
low = re.match(r'HELLO', 'hello world!')
print(large.group()) # hello
print(low.group()) # AttributeError: 'NoneType' object has no attribute 'group'
正则表达式实例
字符匹配
实例 | 描述 |
---|---|
python | 匹配 “python”. |
字符类
实例 | 描述 |
---|---|
[Pp]ython | 匹配"Python"或"python" |
rub[ye] | 匹配"ruby"或"rube" |
[aeiou] | 匹配中括号内的任意一个字母 |
[0-9] | 匹配任何数字。类似于[0123456789] |
[a-z] | 匹配任何小写字母 |
[A-Z] | 匹配任何大写字母 |
[a-zA-Z0-9] | 匹配任何字母及数字 |
[^aeiou] | 除了aeiou字母以外的所有字符 |
[^0-9] | 匹配除了数字外的字符 |
特殊字符
实例 | 描述 |
---|---|
. | 匹配除"\n"之外的任何单个字符。要匹配包括’\n’在内的任何字符,请使用象’[.\n]'的模式。 |
\d | 匹配一个数字字符。等价于[0-9]。 |
\D | 匹配一个非数字字符。等价于[^0-9]。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[\f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等价于[^\f\n\r\t\v]。 |
\w | 匹配包括下划线的任何单词字符。等价于’[A-Za-z0-9_]’。 |
\W | 匹配任何非单词字符。等价于’[^A-Za-z0-9_]’。 |
$ | 匹配输入字符串的结尾位置。如果设置了RegExp对象的Multiline属性,则$也匹配 \n 或 \r 。要匹配$字符本身,请使用 \$。 |
() | 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用\(和\)。 |
* | 匹配前面的子表达式零次或多次。要匹配*字符,请使用 \ *。 |
+ | 匹配前面的子表达式一次或多次。要匹配+字符,请使用 \+。 |
. | 匹配除换行符\n之外的任何单字符。要匹配.,请使用 \.。 |
[ | 标记一个中括号表达式的开始。要匹配[,请使用 \[。 |
? | 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配?字符,请使用 \?。 |
\ | 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如,‘n’匹配字符’n’。’\n’匹配换行符。序列 ‘\\’ 匹配"\",而’\('则匹配"("。 |
^ | 匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 ‘\^’。 |
{ | 标记限定符表达式的开始。要匹配{,请使用 \{。 |
| | 指明两项之间的一个选择。要匹配|,请使用 \|。 |
限定符
实例 | 描述 |
---|---|
* | 匹配前面的子表达式零次或多次。例如,zo*能匹配"z"以及"zoo"。*等价于{0,}。 |
+ | 匹配前面的子表达式一次或多次。例如,'zo+'能匹配"zo"以及"zoo",但不能匹配"z"。+等价于{1,}。 |
? | 匹配前面的子表达式零次或一次。例如,"do(es)?“可以匹配"do”、“does"中的"does”、“doxy"中的"do”。?等价于{0,1}。 |
{n} | n是一个非负整数。匹配确定的n次。例如,'o{2}‘不能匹配"Bob"中的’o’,但是能匹配"food"中的两个o。 |
{n,} | n是一个非负整数。至少匹配n次。例如,'o{2,}‘不能匹配"Bob"中的’o’,但能匹配"foooood"中的所有o。'o{1,}‘等价于’o+’。'o{0,}‘则等价于’o*’。 |
{n,m} | m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,"o{1,3}"将匹配"fooooood"中的前三个o。'o{0,1}'等价于 |
定位符
实例 | 描述 |
---|---|
^ | 匹配输入字符串开始的位置。如果设置了RegExp对象的Multiline属性,^还会与\n或\r之后的位置匹配。 |
$ | 匹配输入字符串结尾的位置。如果设置了RegExp对象的Multiline属性,$还会与\n或\r之前的位置匹配。 |
\b | 匹配一个单词边界,即字与空格间的位置。 |
\B | 非单词边界匹配。 |
非打印字符
实例 | 描述 |
---|---|
\cx | 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。 |
\f | 匹配一个换页符。等价于\x0c和\cL。 |
\n | 匹配一个换行符。等价于\x0a和\cJ。 |
\r | 匹配一个回车符。等价于\x0d和\cM。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[\f\n\r\t\v]。注意Unicode正则表达式会匹配全角空格符。 |
\S | 匹配任何非空白字符。等价于[^\f\n\r\t\v]。 |
\t | 匹配一个制表符。等价于\x09和\cI。 |
\v | 匹配一个垂直制表符。等价于\x0b和\cK。 |
正则表达式模式
模式 | 描述 |
---|---|
^ | 匹配字符串的开头 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 |
[…] | 用来表示一组字符,单独列出:[amk]匹配’a’,‘m’或’k’ |
[^…] | 不在[]中的字符:[^abc]匹配除了a,b,c之外的字符。 |
re* | 匹配0个或多个的表达式。 |
re+ | 匹配1个或多个的表达式。 |
re? | 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 |
re{n} | 精确匹配n个前面表达式。例如,o{2}不能匹配"Bob"中的"o",但是能匹配"food"中的两个o。 |
re{n,} | 匹配n个前面表达式。例如,o{2,}不能匹配"Bob"中的"o",但能匹配"foooood"中的所有o。"o{1,}“等价于"o+”。"o{0,}“则等价于"o*”。 |
re{n,m} | 匹配n到m次由前面的正则表达式定义的片段,贪婪方式 |
a | b |
(re) | 对正则表达式分组并记住匹配的文本 |
(?imx) | 正则表达式包含三种可选标志:i,m,或x。只影响括号中的区域。 |
(?-imx) | 正则表达式关闭i,m,或x可选标志。只影响括号中的区域。 |
(?:re) | 类似(…),但是不表示一个组 |
(?imx:re) | 在括号中使用i,m,或x可选标志 |
(?-imx:re) | 在括号中不使用i,m,或x可选标志 |
(?#…) | 注释. |
(?=re) | 前向肯定界定符。如果所含正则表达式,以 … 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。 |
(?!re) | 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功 |
(?>re) | 匹配的独立模式,省去回溯。 |
\w | 匹配字母数字及下划线 |
\W | 匹配非字母数字及下划线 |
\s | 匹配任意空白字符,等价于[\t\n\r\f]. |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于[0-9]. |
\D | 匹配任意非数字 |
\A | 匹配字符串开始 |
\Z | 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。 |
\z | 匹配字符串结束 |
\G | 匹配最后匹配完成的位置。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如,‘er\b’可以匹配"never"中的’er’,但不能匹配"verb"中的’er’。 |
\B | 匹配非单词边界。‘er\B’能匹配"verb"中的’er’,但不能匹配"never"中的’er’。 |
\n,\t,等. | 匹配一个换行符。匹配一个制表符。等 |
\1…\9 | 匹配第n个分组的内容。 |
\10 | 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。 |
抽取email的正则表达式
email_pattern = '^[*#\u4e00-\u9fa5 a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$'
emails = re.findall(email_pattern, text, flags=0)
抽取phone_number的正则表达式
cellphone_pattern = '^((13[0-9])|(14[0-9])|(15[0-9])|(17[0-9])|(18[0-9])|(19[0-9]))\d{8}$'
phoneNumbers = re.findall(cellphone_pattern, text, flags=0)
抽取身份证号的正则表达式
IDCards_pattern = r'^([1-9]\d{5}[12]\d{3}(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])\d{3}[0-9xX])$'
IDs = re.findall(IDCards_pattern, text, flags=0)
其他正则表达式
# IP地址正则表达式:
re.compile((25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d))
# 腾讯QQ号正则表达式:
re.compile([1-9]([0-9]{5,11}))
# 国内固话号码正则表达式:
re.compile([0-9-()()]{7,18})
# 用户名正则表达式:
re.compile([A-Za-z0-9_\-\u4e00-\u9fa5]+)