Perl 正则表达
Perl 正则表达
1.分隔符 |#
a|b 表示匹配a或者b
2.括号分组#
捕获分组#
通过圆括号 ()
将一个或多个字符或模式组合在一起,形成一个捕获组。例如,(abc)
是一个捕获组,匹配 "abc" 并将其捕获。
捕获组将匹配的内容存储为一个组,可以在正则表达式的匹配结果中引用或提取这些内容。
例如:
User: (\w+), Age: (\d+)
#(\w+) 捕获用户名
#(\d+) 捕获年龄
在编程语言中引用(python):
import re
pattern = r'(hello) (world)'
text = 'hello world'
match = re.search(pattern, text)
if match:
print("完整匹配:", match.group(0)) # 完整匹配的字符串
print("第一个捕获组:", match.group(1)) # 'hello'
print("第二个捕获组:", match.group(2)) # 'world'
非捕获分组#
(?:abc)
,仅用于匹配 "abc" 的组合,但不将其记录为捕获组。这意味着在匹配时不会将这些字符或模式提取到结果中作为单独的组,也就不能单独引用某个组了。
好处:
- 避免不必要的捕获
- 提高性能
- 提升可读性
(?:abc|ABC)def
#直接匹配 abcdef 或者 ABCdef ,不会进行分组
中括号 []
#
定义一个字符集合,表示可以匹配其中任意一个字符。
[a-zA-Z] #可以匹配任何字母(大写或小写)。
大括号 {}
#
用于指定前面元素的重复次数。
{n}
:恰好 n 次{n,}
:至少 n 次{n,m}
:至少 n 次,但不超过 m 次
a{2,4} #匹配 2 到 4 个 a,例如 aa、aaa 或 aaaa。
3.元字符#
元字符:
Perl正则表达式中有一些特殊字符,称为元字符,它们具有特殊的含义。例如:
(句点.):匹配除换行符之外的任意字符。
(星号*):匹配前面的元素任意次。
(加号+):匹配前面的元素一次或多次。
(问号?):匹配前面的元素零次或一次。
(脱字符^):匹配字符串的开头。比如^a只匹配行首的a。放在中括号表示非,比如[^6],表示一个非6的任意字符
(美元符号$):匹配字符串的结尾。比如$a只匹配行尾的a
4.转义字符#
转义字符:
有些字符在正则表达式中具有特殊含义,如果我们要匹配这些特殊字符本身,就需要使用转义字符。在Perl中,转义字符使用反斜杠(\)表示。例如:
\.:匹配句点字符(.)本身。
\/:匹配正斜杠字符(/)本身。
\:匹配反斜杠字符(\)本身。
\(:匹配左括号(
\):匹配右括号)
特殊:
\b字符分界,表示字符的结尾
\d匹配一个数字字符。等价于 [0-9]
\D匹配一个非数字字符。等价于 [^0-9]
\f匹配一个换页符。等价于 \x0c 和 \cL
\n匹配一个换行符,等价于\x0a
\r匹配一个回车符,等价于\x0d
\s匹配任何空白字符,包括空格、制表、换页
\S匹配任何非空白字符。等价于 [^ \f\n\r\t\v]
\t匹配一个制表符。等价于 \x09 和 \cI
\w匹配大小写字母、数字和下划线,等价于 [A-Z a-z 0-9_],\W与\w正好相反,它匹配非大小写字母、数字和下划线
\W匹配非字母、数字、下划线。等价于 [^A-Za-z0-9_]
\s
包括:
- 空格(
' '
) - 制表符(Tab,
\t
) - 换行符(
\n
) - 回车符(
\r
) - 垂直制表符(
\v
) - 换页符(
\f
)
5.修正符#
修正符:
模式修正符 说明
i 表示在和模式进行匹配进不区分大小写
m 将模式视为多行,使用^和$表示任何一行都可以以正则表达式开始或结束
s 如果没有使用这个模式修正符号,元字符中的"."默认不能表示换行符号,将字符串视为单行
x 表示模式中的空白忽略不计
e 正则表达式必须使用在preg_replace($pattern,$replacement ,$str)换字符串的函数中时才可以使用,替换字符串会被当做 PHP 代码执行,例如:$replacement = 'strtoupper("$0")'; // 将匹配到的字符串转换为大写
g 全局匹配,在被查找的字符串中搜索操作将查找所有符合的项,而不仅仅是第一个。
A 以模式字符串开头,相当于元字符^
Z 以模式字符串结尾,相当于元字符$
U 正则表达式的特点:就是比较“贪婪”,使用该模式修正符可以取消贪婪模式
6.贪欲匹配#
想要匹配html标签怎么办?最简单的办法就是下面这样:
/<span><b> hello world!</b></span>/g
如果用正则表达式中的 . 和 + 组合呢?
<.+> #(.是除换行符的任意字符,+是匹配一次或者多次)
匹配结果
<span><b> hello world!</b></span>
包括hello world!全部匹配了,为什么?
贪欲匹配会 ".+" 会尽可能多的去匹配,从s开始一直到>,都是 ".+"匹配的结果
7.懒惰匹配#
在贪欲表达后加?
正则表达式:/<.+?>/g
结果:<span><b></b></span>
由于懒惰匹配会多次回溯,所以存在回溯绕过
if (preg_match('/.+?HACKER/is',$_POST['try'])){
die("你是hacker还敢自报家门呢?");
}
if (!stripos($_POST['try'],'HACKER') === TRUE){
die("你连自己是hacker都不承认,还想要flag呢?");
}
只要超过最大回溯次数1000 000 次,即可绕过限制
try_id = "try"
try_data = "a"*1000001+"HACKER" #回溯到第1000 000个"a"时,不再回溯,直接匹配"HACKER",但是我们有1000 001个"a",所以只能匹配到最后一个"a",匹配不到"HACKER",自然就匹配失败了
res = requests.post(url,data={try_id:try_data})
8.正向断言#
正向后行断言#
语法:`(?<=pattern)`
作用:它指定了一个位置,该位置的前面必须满足指定的模式(pattern)。但它本身不会消耗字符串中的字符。
示例:对于字符串 "version:1.2"
如果要匹配 "version:" 后面的任意内容(除了换行) ,可以使用 (?<=version:).*
正向前行断言#
Positive Lookahead
语法:`(?=pattern)`
作用:它指定了一个位置,该位置的后面必须满足指定的模式(pattern)。但它本身不会消耗字符串中的字符。
示例:对于字符串 `123def`,如果要匹配 `123` 后面的 `def`,可以使用 `123(?=def)`。
9.递归#
先来个最简单的正则表达式递归
字符串 :abc123dsf654wre485wer652
传统作法:\w{3}\d{3}\w{3}\d{3}\w{3}\d{3}\w{3}\d{3}
递归做法:(\w{3}\d{3}|(?R))*
简单的例子
<?php
$string = "some text (aaa(b(c1)(c2)d)e)(test) more text";
preg_match_all("/\((([^()]*|(?R))*)\)/", $string, $matches);
echo '<pre>';
print_r($matches);
echo '</pre>';
?>
(aaa(b(c1)(c2)d)e)
ctf常用的递归
无参数rce,意思就是正则会匹配 这样的格式 : xxxx() 也就是函数的样子
';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])
只不过有一个递归,这个递归在括号里
\( (?R)? \)
(?R)指代的是整个匹配本身,也就是:
[a-z,_]+\( (?R)? \)
后面的问号表示匹配0次或一次
也就是说我们的表达式可以是 : a(b(c())) 无限延续
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!