正则表达式
单字符匹配
| 字符 | 功能 |
|---|---|
| . | 匹配任意一个字符(除了\r和\n) |
| [ ] | 匹配[ ]中列举的字符 |
| \d | 匹配数字(0-9) |
| \D | 匹配非数字 |
| \s | 匹配空白,即空格、tab键、换行符、\r |
| \S | 匹配非空白 |
| \w | 匹配单词字符,即a-z、A-Z、0-9、_、中文字符 |
| \W | 匹配非单词字符 |
| [^x] | 匹配除了x以外的任意字符 |
其中,
\d 等同于[0-9],
\D等同于[^0-9],
\w 等同于[a-zA-Z0-9_],
\W等同于[^a-zA-Z0-9_]。
数量表示
| 字符 | 功能 |
|---|---|
| * | 匹配前一个字符0次或无限次 |
| + | 匹配前一个字符1次或无限次 |
| ? | 匹配前一个字符0次或1次,即要么有要么没有 |
| {m} | 匹配前一个字符出现m次 |
| {m,} | 匹配前一个字符至少出现m次 |
| {m,n} | 匹配前一个字符至少出现m次,至多出现n次 |
其中,
*等同于{0,},
+等同于{1,},
?等同于{0,1}
边界表示
| 字符 | 功能 |
|---|---|
| ^ | 匹配字符串开头 |
| $ | 匹配字符串结尾 |
| \b | 匹配单词的边界 |
| \B | 匹配非单词边界 |
匹配分组
| 字符 | 功能 |
|---|---|
| | | 匹配左右任意一个表达式 |
| (ab) | 把括号中字符作为一个分组 |
| \num | 引用分组num匹配到的字符串 |
| (?P<name>) | 给分组起别名 |
| (?P=name) | 引用别名为name分组匹配到的字符串 |
正则表达式测试
了解了正则表达式的匹配规则,怎么测试编写的正则表达式是否正确呢?一般来说,有三种方式:
(1)下载测试工具测试
这里推荐RegexBuddy。RegexBuddy是一款正则表达式测试工具,支持多种编程语言的正则式测试,匹配结果在原文本中高亮。根据编写的正则式,RegexBuddy还提供相应语言的代码自动生成功能。不过网上下到的破解版该功能可能缺失。
除此之外RegExBuilder也是一款正则表达式测试工具。
(2)编写代码测试
也可以用编程语言,调用相应的函数库编写正则表达式测试。比如python的re模块等等。
(3)使用在线正则表达式网站测试
http://tool.chinaz.com/regex
RegexBuddy工具
打开工具是这样的:

Match模块下,可以选择多种语言(此处选了python)。

单字符匹配
示例1:使用 “.” 进行任意字符匹配

Test下输入要匹配的文本内容。Highlight选中表示在原文中高亮匹配结果(黄蓝均是匹配结果,交错显示),List All 表示在下方列出所有匹配结果。
“.” 匹配任意一个字符(除了\r和\n)
示例2:使用“ [ ]” 匹配[ ]中列举的字符



示例3:使用“ \d” 匹配数字0-9

示例4:使用“ \D” 匹配非数字

可以看到,第一行与第二行之间的换行符也被当成非数字匹配,出现了多个空结果(4个空行)。

选择第二个List All模式查看匹配结果,发现四个空行变成了两行。一行为“\r”符,一行为“\n”符。(\n为换行,相当于按了向下的方向键;\r为回车,相当于光标移至当前行行首)
两种不同查看模式下的行数差异可能是RegexBuddy工具自身格式的原因,这里我们知道“\D”模式下,回车换行符\r、\n都会当成非数字被匹配就可以了。
除此之外,\t(一个tab键)也会当成非数字被匹配。
示例5:使用“ \s” 匹配空白

空白包括空格、\t(一个tab键)、\n、\r。
示例6:使用“ \S” 匹配非空白

示例7:使用“ \w” 匹配单词字符

单词字符包括a-z、A-Z、0-9、下划线_、中文字符。
示例8:使用“ \W” 匹配非单词字符

非单词字符即单词字符以外的所有字符,包括空格、\t、\n、\r。
数量表示
示例1:使用“ *” 匹配前一个字符0次或无限次

这里“ w* ”匹配w出现0次或无限次。虽然待匹配文本“we”中只有一个w,但是匹配结果有两个:一个w,一个为空。
这是因为空结果匹配了w出现了0次的情况,我们可以把每个字符看成是自身和空字符的拼接,使用“ x* ”对字符匹配,若x与字符相同,则返回其本身;若不同,返回一个匹配的空结果。(这里与python里使用re匹配的结果稍有不同,re是即使x与字符相同,对其本身也要进行空字符匹配,即会返回两个结果)。



python的re模块,对文本“e”匹配正则表达式“e*”:
>>> import re
>>> s = re.findall('e*', 'e')
>>> print(s)
['e', '']
可以看到,RegexBuddy对匹配到的字符不再进行空字符匹配,对未匹配到的字符才进行空字符匹配。python的re模块对匹配到的字符和未匹配的字符都会进行空字符匹配。
示例2:使用“ +” 匹配前一个字符1次或无限次

示例3:使用“ ?” 匹配前一个字符0次或1次,即要么有要么没有

涉及到可以0次,所以和“ * ”的匹配非常相似。只是“ * ”可以匹配无限次,“ ?” 最多一次。所以连续出现的字符会被拆开匹配。
示例4:使用“ {m}” 匹配前一个字符出现m次


示例5:使用“ {m,}” 匹配前一个字符至少出现m次

示例6:使用“ {m,n}” 匹配前一个字符至少出现m次,至多出现n次


边界表示
示例1: 使用“^” 匹配字符串开头

示例2:使用 “$” 匹配字符串结尾


复合使用“^”和“$”,匹配以“一”开头,以“三”结尾的句子

示例3:使用 “\b” 匹配单词的边界



“\b”匹配一个单词边界,也就是指单词和空格间的位置。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”(来自维基百科)。
网上有这样一种说法, \b匹配这样的位置:它的前一个字符和后一个字符不是或不存在\w(单词字符,即a-z、A-Z、0-9、_、中文字符)。
示例4:使用 “\B” 匹配非单词边界


“\B”匹配非单词边界。例如,“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。
匹配分组
示例1:使用 “| ” 匹配左右任意一个表达式

示例2:使用 “(ab)” 把括号中的字符作为一个分组






python中的“*”默认贪婪匹配,即有多种字符串序列符合匹配模式时,默认选择最长的序列作为匹配结果。若希望选择最短的序列,需要使用“*?”,开启非贪婪模式。

使用“()”匹配出的结果会作为一个分组,正则表达式中有几个括号对,就会对应几个分组。这里,gropu2对应第二次出现括号对标签所对应的分组,显示匹配结果,则只将第二个分组中匹配的结果展示出来。
示例3:使用 “(?P<name>)” 给分组起别名


Python re模块
可参考:
https://www.runoob.com/python/python-reg-expressions.html
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import re
text_str = '南充高坪机场(Nanchong Gaoping Airport ICAO:ZUNC;IATA:NAO)位于南充市主城区正东方向,距离南充市中心直线' \
'距离7.5公里,交通便利,飞行区等级属于4C级预留4D机场。机场属浅丘地形,机场标高365米,全年平均雾日61.7天,净空条件良' \
'。目前已经成为川渝地区航空客货集散枢纽之一。'
pattern = re.compile(r'\w+')
result = pattern.match(text_str)
print('match结果:{}'.format(result.group()))
result = pattern.search(text_str)
print('search结果:{}'.format(result.group()))
result = pattern.findall(text_str)
print('findall结果:{}'.format(result))
注意,match 和 search 是匹配一次,findall 匹配所有。
输出:

提取文本的省市区地理位置信息
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import re
s = '南充高坪机场(Nanchong Gaoping Airport ICAO:ZUNC;IATA:NAO)位于南充市主城区正东方向,距离南充市中心直线' \
'距离7.5公里,交通便利,飞行区等级属于4C级预留4D机场。机场属浅丘地形,机场标高365米,全年平均雾日61.7天,净空条件良' \
'。目前已经成为川渝地区航空客货集散枢纽之一。'
print(' {}'.format(s))
pattern = r'([0-9\d\a-z\d\u4e00-\u9fa5]{2,15}?(?:省|自治区)){0,1}' \
r'([0-9\d\a-z\d\u4e00-\u9fa5]{2,15}?(?:自治州)){0,1}' \
r'([0-9\d\a-z\d\u4e00-\u9fa5]{2,20}?(?:市)){0,1}' \
r'([0-9\d\a-z\d\u4e00-\u9fa5]{2,20}?(?:区|县|旗)){0,1}' \
r'([0-9\d\a-z\d\u4e00-\u9fa5]{2,10}?(?:州)){0,1}'
location = re.findall(r"位于(.+?)[,|。]", s)
print('location:{}'.format(location))
result = re.search(pattern, location[0])
print(result.groups())
针对pattern的多个正则表达式挨个匹配,结果:

题外话,python的translate() 方法,可以根据参数table给出的表转换字符。
参考:https://www.runoob.com/python3/python3-string-translate.html
import string
s = '南充高坪机场(Nanchong Gaoping Airport ICAO:ZUNC;IATA:NAO)位于南充市主城区正东方向,距离南充市中心直线' \
'距离7.5公里,交通便利,飞行区等级属于4C级预留4D机场。机场属浅丘地形,机场标高365米,全年平均雾日61.7天,净空条件良' \
'。目前已经成为川渝地区航空客货集散枢纽之一。'
print(' {}'.format(s))
# 将原句子中的字母大写转小写
s = s.translate(str.maketrans(string.ascii_lowercase, string.ascii_uppercase, string.punctuation))
print('1.{}'.format(s))
# 抛弃句子中的一些标点符号
s = s.translate(str.maketrans('', '', string.punctuation))
print('2.{}'.format(s))
# 抛弃句子中的数字
s = s.translate(str.maketrans('', '', string.digits))
print('3.{}'.format(s))
# 抛弃句子中的字母
s = s.translate(str.maketrans('', '', string.ascii_uppercase+string.ascii_lowercase))
print('4.{}'.format(s))
# 抛弃句子中的指定字符
s = s.translate(str.maketrans('', '', ';[]:()'))
print('5.{}'.format(s))
输出:

Python 2.0中抛弃标点符号和数字:
text = text.translate(None, string.punctuation)
text = text.translate(None, '1234567890')
Python 3.0等价物:
text = text.translate(str.maketrans('','',string.punctuation))
text = text.translate(str.maketrans('','','1234567890'))
maketrans前两个参数表示“不做任何事情”,第三个参数表示将任何标点或数字转换为None(即删除它们)。
本文深入解析正则表达式的单字符匹配、数量表示、边界表示及匹配分组,涵盖常用正则表达式符号的功能说明,并通过实例演示如何使用Python re模块进行文本匹配。
49万+

被折叠的 条评论
为什么被折叠?



