6

正则表达式知识总结

 3 years ago
source link: https://ihtcboy.com/2020/10/02/2020-10-02_%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB%93/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

正则表达式,如果有一定编程经验的同学,一定知道,可能你知道,但又说不出个所以然来,平时不经常使用,很容易就忘记,有一部分原因,我认为是总结的内容,不够简单和深刻。所以,自己尝试总结一下正则表达式的基础知识点,对于大部分的编程场景应该足够使用啦。另外,也希望通过总结,以便后续忘记时,能快速的记忆起来,这就是本文章的主要内容。

2、正则表达式

RegularExpression.png

匹配字符集

语法 匹配 示例 . 匹配任意字符(除了\n) 表达式:. 匹配任意一个字符 [...] 匹配字符集(... 表示任意字符) 表达式:[a-zA-Z] 匹配任意一个小写或大写的字母。
表达式:[iHTC] 匹配 “i”, “H”, “T” 和 “C”。
表达式:[e-k] 匹配 “e” 到 “k” 之间的字符。 \d 匹配数字 表达式:a\d,匹配字符串 “aaa123” 中的 a1
表达式:a.\d,匹配字符串 “aaa123” 中的 aa1\D 匹配非数字 表达式:a.\D,匹配字符串 “aaa123” 中的 aaa\s 匹配空白字符(包括空格、制表符、换页符等空白字符,[ \t\n\r\f]) 表达式:a.\s,匹配字符串 “aaa 123” 中的 aa(最后是空格) 。 \S 匹配非空白字符 表达式:a.\S,匹配字符串 “aaa 123” 中的 aaa\w 匹配单词字符([a-zA-Z0-9_]和汉字) 表达式:a.\w,匹配字符串 “aaa 123” 中的 aaa\W 匹配非单词字符 表达式:a.\W,匹配字符串 “aaa 123” 中的 aa(最后是空格) 。 \ 转义字符 \r, \n 代表回车和换行符; \t 制表符; \\ 代表 “\” 本身; \^ 匹配 ^ 符号本身; \$ 匹配 $ 符号本身; \. 匹配小数点(.)本身。

匹配量词(Quantifier)

语法 匹配 示例 * 匹配表达式出现 0次或者无限次,相当于 {0,} 表达式:a*,匹配字符串 “aaa123” 中的 aaa+ 匹配表达式至少出现 1次或者无限次,相当于 {1,} 表达式:a+,匹配字符串 “aaa123” 中的 aaa? 匹配表达式 0次或者 1次,相当于 {0,1} 表达式:a?,匹配字符串 “aaa123” 中的 a{m,n} 匹配表达式至少重复 m 次,最多重复 n 次 表达式:a{1,2},匹配字符串 “aaa123” 中的 aa{m} 匹配表达式重复 m 次 表达式:a{3},匹配字符串 “aaa123” 中的 aaa{m,} 匹配表达式至少重复 m 次 表达式:a{1,},匹配字符串 “aaa123” 中的 aaa*? 匹配模式变为非贪婪(尽可能少匹配字符),匹配表达式可以为 0次,也可以是无限次 表达式:a[0-9]*?23',匹配字符串 “aaa123” 中的 a123
如果匹配字符串 “aaa23” 则为 a23
如果匹配字符串 “aaa456123” 则为 a456123+? 匹配模式变为非贪婪(尽可能少匹配字符),匹配表达式至少 1次,也可以是无限次 表达式:a[0-9]+?23,匹配字符串 “aaa123” 中的 a123
如果匹配字符串 “aaa23” 则匹配失败 。
如果匹配字符串 “aaa456123” 则为 a456123?? 匹配模式变为非贪婪(尽可能少匹配字符),匹配表达式最多 1次,也可以是 0次 表达式:a[0-9]??23,匹配字符串 “aaa123” 中的 a123
如果匹配字符串 “aaa23” 则为 a23
如果匹配字符串 “aaa456123” 则匹配失败。 {m,n}? 非贪婪模式,匹配符合的最短的字符串 表达式:a[0-9]{1,4}?23,匹配字符串 “aaa123” 中的 a123
如果匹配字符串 “aaa23” 则匹配失败 。
如果匹配字符串 “aaa456123” 则为 a456123 语法 匹配 示例 ^ 匹配字符串开头 表达式:^\d 表示必须以数字开头。
表达式:[^abc] 匹配 a, b, c 之外的任意一个字符。 $ 匹配字符串结尾 表达式:*.com$ 匹配 .com 结尾的字符串。
\d$表示必须以数字结束。 \A 指定的字符串匹必须出现在开头 表达式:\Aa,匹配字符串 “aaa123” 中的 a\Z 指定的字符串匹必须出现在结尾。如果是存在换行,只匹配到换行前的结束字符串。 表达式:\d\Z,匹配字符串 “aaa123” 中的 3\b 匹配一个单词边界,但只在单词开始或结尾的位置,即匹配 \w\W 之间。(本身不匹配任何字符) 表达式:\b4,匹配字符串 “aaa123 456” 中的 4
表达式:\b5,匹配字符串 “aaa123 456” 则为失败。 \B 匹配非单词边界,但不能在词的开头或者结尾,即匹配 [^\b] 。(本身不匹配任何字符) 表达式:\B4,匹配字符串 “aaa123 456” 则为失败。
表达式:\B5,匹配字符串 “aaa123 456” 中的 5

匹配条件分组

语法 匹配 示例 或关系,匹配左右任意一个表达式 表达式:a⎮b,匹配字符串 “aaa123” 中的 a(ab) 括号中表达式作为一个分组 表达式:(a1),匹配字符串 “aaa123” 中的 a1
表达式:(P⎮p)ython,可以匹配 Python 或者 python(?:exp) 表示非捕获分组,匹配 pattern 但不获取匹配结果。 表达式:([a-z]*)([0-9]*)([a-z]*),匹配字符串 "aaa123def456" 中的 ‘aaa’, ‘123’, ‘def’
表达式:(?:[a-z]*)([0-9]*)([a-z]*),匹配字符串 “aaa123def456” 中的 ‘123’, ‘def’\<number> 引用编号为 number 的分组(规则)匹配到的字符串 表达式:(\d)def\1,匹配字符串 “aaa123def321” 中的 3def3(?P<name>) 给分组起一个别名 name 表达式:(?P<tag>\d)def(?P=tag),匹配字符串 “aaa123def321” 中的 3def3(?P=name) 引用别名为 name 的分组匹配字符串 表达式:<(?P<tag>\w*)>.*</(?P=tag)>,匹配字符串 <html><h1>www.iHTCboy.com</h1><html> 中的 <h1>www.iHTCboy.com</h1> 。 语法 匹配 示例 (?=exp) 断言自身出现的位置的后面能匹配表达式 exp,exp1(?=exp2):查找 exp2 前面的 exp1。 表达式:Windows(?=7) 能匹配Windows7 中的 “Windows”,但不能匹配 Windows10 中的“Windows”。 (?!exp) 断言自身出现的位置的后面不能匹配表达式 exp,exp1(?!exp2):查找后面不是 exp2 的 exp1。 表达式:Windows(?!7) 能匹配Windows10 中的“Windows”,但不能匹配 Windows7 中的“Windows”。 (?<=exp) 断言自身出现的位置的前面能匹配表达式 exp,(?<=exp2)exp1:查找 exp2 后面的 exp1。 表达式:(?<=7)Windows 能匹配 7Windows 中的“Windows”,但不能匹配 10Windows 中的“Windows”。 (?<!exp) 断言自身出现的位置的前面不能匹配表达式 exp,(?<!=exp2)exp1:查找前面不是 exp2 的 exp1。 表达式:(?<!7)Windows 能匹配 10Windows 中的“Windows”,但不能匹配 7Windows 中的“Windows”。

exp :expression(表达式)

类型 模式 说明 IGNORECASE 忽略大小写模式 匹配时忽略大小写。(正则默认是区分大小写的) SINGLELINE 单行模式 整个文本看作一个字符串,只有一个开头一个结尾 MULTILINE 多行模式 每行都是一个字符串。在多行模式下,如果需要仅匹配字符串开始和结束位置,可以使用 \A 和 \Z

3、Python 正则表达式

如果使用编辑语言来执行正则表达式呢?所有语言都是相通的,这是记录了之前使用 Python 的 re 模块做正则匹配的功能。

compile 和 match 函数

re.compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match()、search() 等函数使用。
re.match 尝试从字符串的起始位置匹配一个模式,如果字符串开始不符合正则表达式,就返回 None 。

1
result = re.match(pattern, string)
1
prog = re.compile(pattern)
result = prog.match(string)

注:如果需要多次使用这个正则表达式的话,使用 re.compile() 保存这个正则对象以便复用匹配多个字符串,可以让程序更加高效。

search 函数

re.search 扫描整个字符串并返回第一个成功的匹配。如果没有匹配,就返回一个 None 。

1
re.search(pattern, string, flags=0)
1
>>> re.search('iHTCboy', 'www.iHTCboy.com')
>>> 
<re.Match object; span=(4, 11), match='iHTCboy'>

我们可以使用 group(num)groups() 匹配对象函数来获取匹配表达式。

1
>>> searchObj = re.search( r'(.*) are (.*?) .*', "iHTCboy are my nikename)
>>> print(searchObj.group())
>>> print(searchObj.groups())
>>> print(searchObj.group(1))
>>> print(searchObj.group(2))
>>> 
iHTCboy are my nikename
('iHTCboy', 'my')
iHTCboy
my

findall 函数

re.findall 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。

1
re.findall(pattern, string, flags=0)

string 返回一个不重复的 pattern 的匹配列表, string 从左到右进行扫描,匹配按找到的顺序返回。如果样式里存在一到多个组,就返回一个组合列表;就是一个元组的列表(如果样式里有超过一个组合的话)。空匹配也会包含在结果里。

比如查找字符串中的所有数字:

1
>>> result2 = re.findall(r'\d+', 'abc123d4efg567')
>>> 
['123', '4', '567']

查找不是以 4、7 结尾的手机号码(11位)手机号码:

1
>>> result2 = re.findall(r'^1\d{9}[0-35-68-9]$', 'xxxxx')
>>>

finditer 函数

和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。

1
re.finditer(pattern, string, flags=0)

搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器:

1
2
3
4
5
6
>>> for m in re.finditer(r'\d+', 'abc123d4efg567'):
>>> print(m.group())
>>>
123
4
567

split 函数

re.split 方法按照能够匹配的子串将字符串分割后返回列表。

1
re.split(pattern, string, maxsplit=0, flags=0)

pattern 分开 string 。如果 maxsplit 非零, 最多进行 maxsplit 次分隔, 剩下的字符全部返回到列表的最后一个元素。

对于规则的字符串,比如 abc 我们一般可以用 split 函数分割,但是如果遇到 a b c 这样的字符串,得到的结果就是 ['a', 'b', '', '', 'c']。所以,你可能需要人工来自己再次过滤,而使用正则表达式来处理,就显示很轻松:

1
>>> re.split(r'[\s\,]+', 'a,b, c  d')
>>> 
['a', 'b', 'c', 'd']

上面的 [\s\,]+ 表示匹配 \s (空格)和 , 中任意一个至少一次的分割。

对于一个找不到匹配的字符串而言,split 不会对其作出分割。

1
>>> re.split('a*', 'hello iHTCboy')
>>> 
['hello iHTCboy']

sub 函数

re.sub 用于替换字符串中的匹配项。

1
re.sub(pattern, repl, string, count=0, flags=0)

返回通过使用 repl 替换在 string 最左边非重叠出现的 pattern 而获得的字符串。 如果样式没有找到,则不加改变地返回 string。 repl 可以是字符串或函数;如为字符串,则其中任何反斜杠转义序列都会被处理。 也就是说,\n 会被转换为一个换行符,\r 会被转换为一个回车附,依此类推。

比如电话号码格式可能带有空格或者-时,可以替换为空字符串:

1
>>> re.sub(r'\D', "", "188-8888-8888")
>>> 
18888888888

repl 参数可以是一个函数,用于对匹配的内容进行更多的逻辑处理:

1
# 将匹配的数字乘以 2
>>> def double(matched):
>>>     value = int(matched.group('value'))
>>>     return str(value * 2)
>>>  
>>> re.sub('(?P<value>\d+)', double, 'abc123d4efg567')
>>> 
abc246d8efg1134

正则表达式的内容有非常的多,如果不经常使用的话,可以就会很快忘记。所以,正则其实是不是应该记住呢?其实,应该是要记住,如果记不住,要不要紧?其实,是不要紧,因为正则就想查表一下,你如果之前已经比较系统的学习过,忘记了规则,看一下本文就大概记起来了。所以,这就是本文的目的,总结性的文章,不需要太多的复杂,简单又快捷的总结。

国庆中秋双节快乐!这篇文章应该是去年9月就定下来但迟迟没有动手,现在又过一年了,感叹生活真快。好好学习,天天快乐~

  • 如有疑问,欢迎在评论区一起讨论!
  • 如有不正确的地方,欢迎指导!

注:本文首发于 iHTCboy’s blog,如若转载,请注来源


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK