引言
本文主要介绍一下 Python 正则表达式,搜索模式匹配。更多 Python 进阶系列文章,请参考 Python 进阶学习 玩转数据系列
内容提要:
-
re 模块方法汇总
-
match() vs. search()
-
常用的正则表达式通配符
-
用 Raw Strings 原始字符串
-
MatchObject
-
findall()
-
Matching Flags
re.IGNORECASE
re.ASCII
re.DOTALL
re.MULTILINE
re.VERBOSE -
字符串操作 re.sub re.split
-
用 re.compile 更方便
-
字符串方法 和 正则匹配
-
匹配 Email 的例子
-
正则表达式基本语法应用
简单字符匹配
一些特殊意义的字符
[ ] 中括号 Square brackets
重复通配符 Wildcards match repeated characters
命名提取匹配部分 Naming extracted components
re 模块方法汇总
Method | Description |
---|---|
match (pattern, string, flags) | From the beginning , return MatchObject if a match exists, None otherwise |
search (pattern, string, flags) | Search the entire string for match, return MatchObject if exists, None otherwise |
findall (pattern, string, flags) | Return a list of matches of the pattern within string |
finditer (pattern, string, flags) | Iterator of matches of patterns in string |
fullmatch (pattern, string, flags) | Apply pattern to full string, MatchObject or None returned |
split (pattern, string, maxsplit, flags) | Break string up by regex pattern |
sub (pattern, repl, string, count, flags) | Find match, replace it with repl. Return new string |
match() vs. search()
match() :
● 返回一个 MatchObject 如果 0 或 多个字符从字符串起始位置
匹配到正则表达式模式
● 返回 None 如果字符串起始位置
没有匹配到模式
search() 扫描正个字符串返回:
● 一个相应的 MatchObject
● None 没有找到匹配到的
举例:
Code:
import re
def match_search(regex, search_str):
if re.match(regex, search_str):
print('match: begins with {0}'.format(regex))
else:
print('match: {0} not found at beginning'.format(regex))
if re.search(regex, search_str):
print('search: contains {0}'.format(regex))
else:
print('search: {0} not found within'.format(regex))
lor = '''THE LORD OF THE RINGS
V*art One
THE FELLOWSHIP
OF THE RING
J.R.R.ToIkien'''
match_search('THE', lor)
match_search('THE LORD', lor)
match_search('LORD', lor)
match_search('ToIkien', lor)
regex = re.compile('\s+')
for s in [" ", "abc ", " abc"]:
if regex.match(s):
print(repr(s), "matches")
else:
print(repr(s), "does not match")
常用的正则表达式通配符
Meta Character | Description |
---|---|
^ | from the start |
$ | to the end |
\s | whitespace |
\S | non-whitespace |
\d | digit |
\D | non-digit |
\w | alpha-numeric character |
\W | non-alpha-numeric character |
\b | word boundary |
\B | non-word boundary |
. | none-line break charcter |
* | 0 or more characters |
+ | 1 or more characters |
? | 0 or 1 character |
{n} | exactly n characters |
{n,m} | from n to m characters |
{,m} | up to m characters |
`(n | m |
[abcd] | a or b or c or d |
[f-m] | one of characters from f through m |
[^xyz] | not x or y or z |
[a-zA-Z] | one of any letters |
用 Raw Strings 原始字符串
● \ 反斜杠 backslash ,在字符串中是转义符,而在正则表达式中一个特殊的字符。
● 为了避免混淆反斜杠和转义字符,我们用原始字符串 Raw String
● 用 r’….’ 表示原始字符串 ,\
在原始字符串不再是一个特殊字符串字符。
举例:
字符串中 \b
是一个特殊的符号,\\
是表示字符 \,强调用不是转义符。
MatchObject
match() 或 search() 会返回一个 MatchObject
MatchObject 方法:
● start(n) – 返回特定分组的起始索引
● end(n) – 返回特定分组的终止索引
● span(n) – 返回特定分组的起止索引元组 values (start, end)
● groups() – 返回包含所有子分组的元组
● group(n) – 返回特定子分组的元组, zero is the whole match
举例:
代码:
matchobj = re.search(r'(\w+) (\w+) (\w+) (\w+)',
"Hobbits are an unobtrusive but very ancient people")
print("groups():",matchobj.groups())
for i in range(len(matchobj.groups())+1):
print("group({0}): {1}".format(str(i), matchobj.group(i)))
print("start({}): {}".format(str(i), matchobj.start(i)))
print("end({}): {}".format(str(i), matchobj.end(i)))
findall()
findall() 返回一个 list,是括号所匹配到的结果(如 matches_2),多个括号就会返回多个括号分别匹配到的结果(如 matches_3),如果没有括号就返回就返回整条语句所匹配到的结果(如 matches_1)。
第 1 个 regex 中不带有括号
, 其输出的内容就是整个表达式所匹配到的内容。
第 2 个 regex 中带有1个括号
,其输出的内容就是括号匹配到的内容,而不是整个表达式所匹配到的结果。
第 3 个 regex 中是带有2个括号
的,我们可以看到其输出是一个list 中包含 2 个 tuple
Code:
import re
string = "Hobbits are an unobtrusive but very ancient people"
matches_1 = re.findall(r'\w+', string)
matches_2 = re.findall(r'(\w+) (\w+) (\w+) (\w+)', string)
matches_3 = re.findall(r'((\w+) (\w+) (\w+) (\w+))', string)
print("{0}\ncontains {1} words: {2}".format(string, len(matches_1), matches_1))
print("{0}\ncontains {1} words: {2}".format(string, len(matches_2), matches_2))
print("{0}\ncontains {1} words: {2}".format(string, len(matches_3), matches_3))
Matching Flags
● re.IGNORECASE - 忽略大小写 匹配
● re.ASCII - 只匹配 ASCII,而不是 unicode
● re.VERBOSE - use verbose-style regular expressions
● re.DOTALL - dot(.) 匹配任意字符,包括换行符
● re.MULTILINE - 多行匹配每行的开头或结尾
re.IGNORECASE
re.IGNORECASE 或简写为 re.I ,忽略大小写匹配。
re.ASCII
re.ASCII 或简写为 re.A ,ASCII表示ASCII码的意思,让 w, W, b, B, d, D, s和 S只匹配ASCII,而不是Unicode
re.DOTALL
re.DOTALL 或简写为 re.S,DOT表示 .
,ALL表示所有,连起来就是.
匹配所有,包括换行符n。默认模式下.
是不能匹配行符 n 的。
re.MULTILINE
re.MULTILINE 或简写为 re.M,多行模式,当某字符串中有换行符 n,默认模式下是不支持换行符特性的,比如:行开头 和 行结尾,而多行模式下是支持匹配行开头的。
re.VERBOSE
通常正则表达式都是一行,不是很好理解。所以,可以使用详细模式,正则表达式中可以加注解。但是详细模式有区别普通模式:
空格被忽略:
● 空格,tabs 符,回车符都会被胡烈
● 如果需要忽略一个空格,需要用转义符。
注释被忽略:
● 详细模式中,一个注释就像 Python 代码中的注释一样,以 # 开头直到行结束。
代码:
import re
pattern = r'''
(\(?\d{3}\)?)? # optional area code, parentheses optional
[-\s.]? # optional separator, dash, space, or period
\d{3} # 3-digit prefix
[-\s.] # separator: dash, space or period
\d{4} # final 4-digits
'''
phones = [
'123-456-7890',
'123 456 7890',
'(123) 456-7890',
'123.456,7890',
'123-4567',
'abc-dfg-7789'
]
valid = [ph for ph in phones if re.match(pattern, ph, re.VERBOSE)]
print('VERBOSE: Valid phones: {0}'.format(valid))
字符串操作 re.sub re.split
有两种方法用来处理经过模式匹配后的字符串
- newstr = re.sub (pattern, replacement, sourcestring) 替换模式匹配到的字符
- re.split (pattern, sourcestring) 用模式匹配到的作为分隔符
举例:
用 re.compile 更方便
如果一个匹配模式需要反复使用,那么用 re.compile(pattern) 更方便
pattern_obj = re.compile(pattern, re.VERBOSE)
举例:
字符串方法 和 正则匹配
regex.search() 方法和 str.index() 或 str.find() 方法是相同功能的。
regex.sub() 方法像 str.replace()
匹配 Email 的例子
‘\w+@\w+.[a-z]{3}’ \w 只能匹配到字符,数字的字符,邮件里的 .
字符没法匹配到
我们可以用 \S 匹配非空字符。
‘\w+\S\w+@\w+.[a-z]{3}’
正则表达式基本语法应用
简单字符匹配
import re
lor = open('../Python_data_wrangling/Python_data_wrangling_data_raw/data_raw/LordOfTheRings.txt',encoding='utf-8').read()
frodo = re.compile('Frodo')
frodos = frodo.findall(lor)
gandalf = re.compile('Gandalf')
gandalfs = gandalf.findall(lor)
sauron = re.compile('Sauron')
saurons = sauron.findall(lor)
gollum = re.compile('Gollum')
gollums = gollum.findall(lor)
print("Frodo is mentioned {} times\nGandalf is mentioned {} times\nSauron is mentioned: {} times\nGollum is mentioned {} times".
format(len(frodos),len(gandalfs), len(saurons), len(gollums)))
print("So who is the Lord of the Rings?")
输出:
Frodo is mentioned 1100 times
Gandalf is mentioned 466 times
Sauron is mentioned: 60 times
Gollum is mentioned 72 times
So who is the Lord of the Rings?
一些特殊意义的字符
如: ^ $ * + ? { } [ ] \ | ( )
如果只是想匹配到上面的这些字符,不能直接直接用,需要加上转义符 \
[ ] 中括号 Square brackets
如果内置的字符不够充分,用户可以自定义。可以用破折号表示范围
如 “[a-m]” 匹配小写字符 a 到 m 之间的字符
重复通配符 Wildcards match repeated characters
如果想匹配 5 个字符,可以用 “\w\w\w\w\w” 或 “\w{3}”
Character | Description | Example |
---|---|---|
? | Match 0 or 1 repetitions of preceding | “ab?” matches “a” or “ab” |
* | Match 0 or more repetitions of preceding | “ab*” matches “a”, “ab”, “abb”, “abbb”… |
+ | Match 1 or more repetitions of preceding | “ab+” matches “ab”, “abb”, “abbb”… but not “a” |
{n} | Match n repetitions of preeeding | “ab{2}” matches “abb” |
{m,n} | Match between m and n repetitions of preceding | “ab{2,3}” matches “abb” or “abbb” |
例如:
[\w.]+ 表示 \w 或 . 出现一次或多次,也就能匹配到任意长度字符数字或 .
命名提取匹配部分 Naming extracted components
用 (?P<name>)
来将匹配的值分组成一个字典
code:
import re
email4 = re.compile('(?P<user>[\w.]+)@(?P<domain>\w+)\.(?P<suffix>[a-z]{3})')
match = email4.match('peter.zhang@gmail.com')
match.groupdict()