最详解的正则表达式------贪婪和非贪婪、转义符、分组

简介: 贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。 非贪婪模式只被部分NFA引擎所支持

贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。 非贪婪模式只被部分NFA引擎所支持


尽可能多的重复:贪婪模式

*, + , ?, {n,m}, {n,}, {,m}: 尽可能多的去重复, 贪婪模式

[root@whl ~]# echo "aaaaaaaaaa" | grep -Eo 'a?'
a
a
a
a
a
a
a
a
a
a
[root@whl ~]# echo "aaaaaaaaaa" | grep -Eo 'a+'
aaaaaaaaaa
[root@whl ~]# echo "aaaaaaaaaa" | grep -Eo 'a*'
aaaaaaaaaa
[root@whl ~]# echo "aaaaaaaaaa" | grep -Eo 'a{3,}'
aaaaaaaaaa
[root@whl ~]# echo "aaaaaaaaaa" | grep -Eo 'a{3,4}'
aaaa
aaaa

尽可能少的重复:非贪婪模式

非贪婪模式:*?, +?, ??, {n,m}?, {n,}?, {,m}?: 尽可能少的去匹配

[root@node1 20221120]# echo "aaaaaa" | grep -Po "a*?"
#=# a*? -> a*? -> a-> 重复0次
[root@node1 20221120]# echo "aaaaaa" | grep -Po "a+?"
# a+? -> a+? -> a+-》 只重复1次
a
a
a
a
a
a
[root@node1 20221120]# echo "aaaaaa" | grep -Po "a??"
# a??-> a??-> a->重复0次
[root@node1 20221120]# echo "aaaaaa" | grep -Po "a{3,6}?"
# a{3,6}? -> a-》 重复3次
aaa
aaa
[root@node1 20221120]# echo "aaaaaa" | grep -Po "a{,6}?"
# a{,6} -> 最少次数0次-》 a重复0次,也是没有
[root@node1 20221120]# echo "aaaaaa" | grep -Po "a{3,}?"
# a{3,} -> 最少重复3次,-》 a重复3次, 匹配到3个aaa
aaa
aaa

转义符

转义符:

\A: 匹配字符串的开始和^的用途一样

[root@whl ~]# echo 'hello world' | grep -P '\Ahello'
hello world

\b: 匹配空字符,单词开始或结束

[root@whl ~]# echo 'hello world 123' | grep -P '\bworld\b'
hello world 123
[root@whl ~]# echo 'hello world1123' | grep -P '\bworld\b'
[root@whl ~]# 

\B: 匹配非空字符串,即不是单词的开始或结束

[root@whl ~]# echo 'hello world1123' | grep -P 'world\B'
hello world1123
[root@whl ~]# echo 'hello world1123' | grep -P '\Bworld\B'
[root@whl ~]# echo 'hello world1123' | grep -P '\bworld\B'
hello world1123
[root@whl ~]# echo 'hello world!' | grep -P '\bworld\B'
[root@whl ~]# echo 'hello world!' | grep -P '\bworld\b'
hello world!
[root@whl ~]# echo 'hello world!' | grep -P '\Bworld\B'

\d: 匹配数字[0-9]

[root@whl ~]# echo "1234567890" | grep -Po '\d+'
1234567890

\D:匹配非数字

[root@whl ~]# echo "123,./<>asd" | grep -Po '\D+'
,./<>asd

\s: 匹配空格,制表符,换行

printf "123\n456" | grep -Poz "\d{3}\s\d{3}"
Treat input and output data as sequences of lines, each terminated by a zero byte  (the  ASCII  NUL  character)  instead  of  a newline.

使用了一个-z的选项:

对待输入和输出是一个多行的序列的时候, 用一个zero byte ascii码的空字符, 来代替新的行

123\n456 ->

123 -> 行的序列: 123 -》 123\n456 -> 匹配到123

456 456 456

[root@whl ~]# echo -e "123\t456\n789" | grep -Pz '\d{3}\s\d{3}\s\d{3}'
123 456
789

\S: 匹配非空格字符 \s的补集

[root@whl ~]# echo -e '456zxc789' | grep -Po '\d{3}\S+\d{3}'
456zxc789

\w: 匹配数字,字母和下划线

[root@whl ~]# echo -e '456zxc789_?><sd' | grep -Po '\w+'
456zxc789_
sd

\W: 匹配\w的补集

[root@whl ~]# echo -e '456zxc789_?><sd' | grep -Po '\W+'
?><

\Z: 匹配单词的结束

[root@whl ~]# echo -'hello asdas' | grep -Po 'asdas\Z'
asdas
[root@whl ~]# echo -'hello asdas' | grep -Po 'asdas$'
asdas

分组

分组:使用的语法:()-》 如果一个正则表达式中出现了多个小括号,代表多个分组

a(b(c(d)))e


意味着有是三个分组:怎么去引用这个分组:

组名:手动去命名

组号:自动帮我们编号的: 从左到右去数左括号:第一个左括号:代表分组1,第二个左括号代表分组2, 一次类推

疑问:分组0去哪儿了?分组0: 只的匹配成功的整个字符串

引用的时候:使用\number来引用

[root@whl ~]# echo "abcde" | grep -P "a(b(c(d)))e"
abcde
[root@whl ~]# echo "abcdebcd" | grep -P "a(b(c(d)))e\1"
abcdebcd
[root@whl ~]# echo "abcdebcdcd" | grep -P "a(b(c(d)))e\1\2"
abcdebcdcd
[root@whl ~]# echo "abcdebcdcdd" | grep -P "a(b(c(d)))e\1\2\3"
abcdebcdcdd

(?:…):非捕获版本,分组不能被引用

[root@asdhgsgdasjkkadfhl ~]# echo 'abcdebcd' | grep -P 'a(b(c(d)))e\1'
abcdebcd
[root@asdhgsgdasjkkadfhl ~]# echo 'abcdebcd' | grep -P 'a(?:b(c(d)))e\1'
[root@asdhgsgdasjkkadfhl ~]# 

(?P…)分组命名

引用两种方式:通过组号引用:\number

通过组名引用:(?P=name)

[root@asdhgsgdasjkkadfhl ~]# echo 'abcdebcd' | grep -P 'a(?P<g1>b(c(d)))e\g1'
abcdebcd
[root@asdhgsgdasjkkadfhl ~]# echo 'abcdebcd' | grep -P 'a(?P<g1>b(c(d)))e(?P=g1)'
abcdebcd

(?#…)注释,不参加匹配

[root@asdhgsgdasjkkadfhl ~]# echo 'abcdebcd' | grep -P 'a(?#grop1)(?P<g1>b(c(d)))e(?P=g1)'
abcdebcd

(?=…)正向预搜索,即判定条件, 它不消耗我们的分组: 只做判定条件不返回

windows10 windows98 windows99 -> 当windows后面是10的时候,给我返回windows, 说明了我们匹配的时候:windows10 -》 先去判定windows之后是10的话,匹配成功,且返回内容不包含10

[root@asdhgsgdasjkkadfhl ~]# echo 'w13' | grep -P 'w(?=12)'
[root@asdhgsgdasjkkadfhl ~]# echo 'w12' | grep -P 'w(?=12)'
w12

(?!…) 对正向预搜索的取非, windows(?=10) -> windows(?!10)

> [root@asdhgsgdasjkkadfhl ~]# echo 'w32' | grep -Po 'w(?!32)'
> [root@asdhgsgdasjkkadfhl ~]# echo 'w10' | grep -Po 'w(?!32)' w

(?<=…)反向预搜索:Linux8, window8, mac8 -> 如果我的8前面是Linux时候匹配成功,返回8,不消耗分组内容

[root@asdhgsgdasjkkadfhl ~]# echo 'Linux8' | grep -Po '(?<=Linux)8'
8
[root@asdhgsgdasjkkadfhl ~]# echo 'M8' | grep -Po '(?<=Linux)8'

(?<!…)反向预搜索的取非:

取非(?<=Linux)8-> (?<!Linux)8, 8前面不是Linux的时候,匹配成功

[root@asdhgsgdasjkkadfhl ~]# echo 'M8' | grep -Po '(?<!Linux)8'
8
[root@asdhgsgdasjkkadfhl ~]# echo 'Linux8' | grep -Po '(?<!Linux)8'
[root@asdhgsgdasjkkadfhl ~]# 

(?(id/name)yes-pattern|no-pattern)

id和name指的就是分组的组号和组名

如果这个分组可以匹配得到:执行yes-pattern, 匹配不到: 执行no-pattern

[root@asdhgsgdasjkkadfhl ~]#  echo "<user@host.com>" | grep -P '(<)?(user@host.com)(?(1)>)|$'
<user@host.com>
[root@asdhgsgdasjkkadfhl ~]#  echo "user@host.com" | grep -P '(<)?(user@host.com)(?(1)>)|$'
user@host.com


相关文章
|
6月前
正则表达式分组
正则表达式分组
244 48
|
6月前
|
数据采集 算法 Java
Java 正则表达式【匹配与分组基本原理】
Java 正则表达式【匹配与分组基本原理】
|
Python
136 python高级 - 正则表达式(匹配分组)
136 python高级 - 正则表达式(匹配分组)
48 0
|
PHP 开发者
你见过这些正则表达式中奇奇怪怪的匹配模式吗 _ 贪婪匹配、懒惰匹配 、禁止贪婪匹配!
一篇文章让你清楚的了解正则表达式中奇奇怪怪的匹配模式-- 贪婪匹配、懒惰匹配 、禁止贪婪匹配!
85 1
你见过这些正则表达式中奇奇怪怪的匹配模式吗 _ 贪婪匹配、懒惰匹配 、禁止贪婪匹配!
|
6月前
|
机器学习/深度学习 Java 索引
39、一篇文章弄懂 Java 正则表达式中的量词、贪婪、勉强、独占和 String 的 matches 方法的底层【个人感觉非常值得学习】
39、一篇文章弄懂 Java 正则表达式中的量词、贪婪、勉强、独占和 String 的 matches 方法的底层【个人感觉非常值得学习】
66 0
|
6月前
|
Java 索引
正则表达式源码分析--三个常用类--分组、捕获、反向引用--String 类中使用正则表达式的代码示例和图
正则表达式源码分析--三个常用类--分组、捕获、反向引用--String 类中使用正则表达式的代码示例和图
81 0
|
6月前
|
数据采集 Java API
Java 正则表达式【非贪婪匹配、格式验证、反向引用、API】
Java 正则表达式【非贪婪匹配、格式验证、反向引用、API】
|
Python
138 python高级 - 正则表达式(贪婪和非贪婪)
138 python高级 - 正则表达式(贪婪和非贪婪)
51 0
|
Python
【从零学习python 】68. Python正则表达式中的贪婪和非贪婪模式
【从零学习python 】68. Python正则表达式中的贪婪和非贪婪模式
82 2
|
Go Python
全网最易懂的正则表达式教程(8 )- 贪婪模式和非贪婪模式
全网最易懂的正则表达式教程(8 )- 贪婪模式和非贪婪模式
312 0
全网最易懂的正则表达式教程(8 )- 贪婪模式和非贪婪模式