CTF中经常出现的正则,基础薄弱。突击学习下记点笔记。
PHP正则
PCRE库函数中,正则匹配模式使用分隔符与元字符组成。
分隔符
分隔符可以是非数字、非反斜线、非空格的任意字符。经常使用的分隔符是正斜线(/)、hash符号(#) 以及取反符号(~),例如:
1 | /foo bar/ |
如果模式中包含分隔符,则分隔符需要使用反斜杠()进行转义。
1 | /http:\/\// |
如果模式中包含较多的分割字符,建议更换其他的字符作为分隔符,也可以采用preg_quote进行转义。
1 | $p = 'http://'; |
除了上面提到的分隔符,也可以使用括号样式的分隔符,左括号和右括号分别作为开始和结束 分隔符。
1 | {this is a pattern} |
分隔符后面可以使用模式修饰符(i,m,s,x等)。例如使用 i 修饰符可以忽略大小写匹配:
1 | $str = "Http://www.imooc.com/"; |
元字符
一些字符被赋予 特殊的涵义,使其不再单纯的代表自己,模式中的这种有特殊涵义的编码字符 称为 元字符。
共有两种不同的元字符:一种是可以在模式中方括号外任何地方使用的,另外一种 是需要在方括号内使用的。
在方括号外使用的元字符如下:
**
一般用于转义字符
^
断言目标的开始位置(或在多行模式下是行首)
$
断言目标的结束位置(或在多行模式下是行尾)
.
匹配除换行符外的任何字符(默认)
[
开始字符类定义
]
结束字符类定义
|
开始一个可选分支
(
子组的开始标记
)
子组的结束标记
?
作为量词,表示 0 次或 1 次匹配。位于量词后面用于改变量词的贪婪特性。 (查阅量词)
*
量词,0 次或多次匹配
+
量词,1 次或多次匹配
{
自定义量词开始标记
}
自定义量词结束标记
模式中方括号内的部分称为“字符类”。 在一个字符类中仅有以下可用元字符:
**
转义字符
^
仅在作为第一个字符(方括号内)时,表明字符类取反
-
标记字符范围
转义序列
*
换行 (十六进制 0A)
*车 (十六进制 0D)
*平制表符 (十六进制 09)
*
hh十六进制编码的字符,详细查看unicode properties 属性
*
ddd八进制编码的字符,或者后向引用
\040
空格的另外一种用法
\40
当提供了少于40个子组时也认为是空格。
*意十进制数字
*
任意非十进制数字
*意水平空白字符(since PHP 5.2.4)
*意非水平空白字符(since PHP 5.2.4)
*
任意空白字符
*
任意非空白字符
*意垂直空白字符(since PHP 5.2.4)
*
任意非垂直空白字符(since PHP 5.2.4)
*
任意单词字符
*
任意非单词字符
*词边界
*
非单词边界
*
目标的开始位置(独立于多行模式)
*
目标的结束位置或结束处的换行符(独立于多行模式)
*
目标的结束位置(独立于多行模式)
*目标中首次匹配位置
字符类
方括号标记开始结束。一个按类而不是按顺序匹配的规则。如
[A-Z0-9]可以匹配A-Z或0-9之中的所有内容,而不是按顺序先匹配字母再匹配数字。
可选路径
竖线用于分离模式中的可选路径。 比如模式gilbert|Sullivan匹配 ”gilbert” 或者 ”sullivan”。匹配的处理从左到右尝试每一个可选路径,并且使用第一个成功匹配的。
修饰符
i | 不区分大小写(ignore) for PCRE_CASELESS |
---|---|
m | 多行匹配(more) for PCRE_MULTILINE |
s | 句点使用时匹配包含换行符 for PCRE_DOTALL |
x | 将模式中的空白忽略 for PCRE_EXTENDED |
U | 只匹配最近的一个字符串;不重复匹配 for PCRE_UNGREEDY |
X | 任意反斜线后接没有特殊含义的字符会导致一个错误 for PCRE_EXTRA |
J | 允许子组重名 for PCRE_INFO_JCHANGED |
e was DEPRECATED in PHP 5.5.0, and REMOVED as of PHP 7.0.0. 如果设置了这个被弃用的修饰符, preg_replace() 在进行了对替换字符串的 后向引用替换之后, 将替换后的字符串作为php 代码评估执行(eval 函数方式),并使用执行结果 作为实际参与替换的字符串。单引号、双引号、反斜线(**)和 NULL 字符在 后向引用替换时会被用反斜线转义.详见php手册。
A (PCRE_ANCHORED) 如果设置了这个修饰符,模式被强制为"锚定"模式,也就是说约束匹配使其仅从 目标字符串的开始位置搜索。这个效果同样可以使用适当的模式构造出来,并且 这也是 perl 种实现这种模式的唯一途径。
U (PCRE_UNGREEDY) 这个修饰符逆转了量词的"贪婪"模式。 使量词默认为非贪婪的,通过量词后紧跟? 的方式可以使其成为贪婪的。这和 perl 是不兼容的。 它同样可以使用 模式内修饰符设置 (?U)进行设置, 或者在量词后以问号标记其非贪婪(比如.*?)。
子组
子组通过圆括号分隔界定,并且它们可以嵌套。 将一个模式中的一部分标记为子组(子模式)主要是来做两件事情:
- 将可选分支局部化。比如,模式cat(arcat|erpillar|)匹配 ”cat”, “cataract”, “caterpillar” 中的一个,如果没有圆括号的话,它匹配的则是 ”cataract”, “erpillar” 以及空字符串。
- 将子组设定为捕获子组(向上面定义的)。当整个模式匹配后, 目标字符串中匹配子组的部分将会通过 pcre_exec()() 的 ovector 参数回传给调用者。 左括号从左至右出现的次序就是对应子组的下标(从 1 开始), 可以通过这些下标数字来获取捕获子模式匹配结果。
为了方便简写,如果需要在非捕获子组开始位置设置选项, 选项字母可以位于 ? 和 : 之间,比如:
1 | (?i:saturday|sunday) |
注释
字符序列(?#标记开始一个注释直到遇到一个右括号。不允许嵌套括号。 注释中的字符不会作为模式的一部分参与匹配。如:/te(?# comments)st/
递归模式
(?R) 套个娃。
贪婪模式与懒惰模式
正则表达式中每个元字符匹配一个字符,当使用+之后将会变的贪婪,它将匹配尽可能多的字符,但使用问号?字符时,它将尽可能少的匹配字符,既是懒惰模式。
- 贪婪模式:在可匹配与可不匹配的时候,优先匹配 //下面的
1 | $p = '/\d+\-\d+/'; |
- 懒惰模式:在可匹配与可不匹配的时候,优先不匹配
1 | $p = '/\d?\-\d?/'; |
当我们确切的知道所匹配的字符长度的时候,可以使用{}指定匹配字符数
1 | $p = '/\d{3}\-\d{8}/'; |
使用正则进行匹配
preg_match用来执行一个匹配,可以简单的用来判断模式是否匹配成功,或者取得一个匹配结果,他的返回值是匹配成功的次数0或者1,在匹配到1次以后就会停止搜索。
1 | $subject = "abcdef"; |
上面的代码简单的执行了一个匹配,简单的判断def是否能匹配成功,但是正则表达式的强大的地方是进行模式匹配,因此更多的时候,会使用模式:
1 | $subject = "abcdef"; |
查找所有匹配结果
preg_match只能匹配一次结果,但很多时候我们需要匹配所有的结果,preg_match_all可以循环获取一个列表的匹配结果数组。
1 | $p = "|<[^>]+>(.*?)</[^>]+>|i"; |
可以使用preg_match_all匹配一个表格中的数据:
1 | $p = "/<tr><td>(.*?)<\/td>\s*<td>(.*?)<\/td>\s*<\/tr>/i"; |
\(matches结果排序为\)matches[0]保存完整模式的所有匹配, $matches[1] 保存第一个子组的所有匹配,以此类推。
正则表达式的搜索和替换
正则表达式的搜索与替换在某些方面具有重要用途,比如调整目标字符串的格式,改变目标字符串中匹配字符串的顺序等。
例如我们可以简单的调整字符串的日期格式:
1 | $string = 'April 15, 2014'; |
其中${1}与$1的写法是等效的,表示第一个匹配的字串,$2代表第二个匹配的。
通过复杂的模式,我们可以更加精确的替换目标字符串的内容。
1 | $patterns = array ('/(19|20)(\d{2})-(\d{1,2})-(\d{1,2})/', |
//详细解释下结果:(19|20)表示取19或者20中任意一个数字,()表示两个数字,()表示1个或2个数字,()表示1个或2个数字。^表示以任意空格开头的,并且包含在{}中的字符,并且以任意空格结尾的,最后有个=号的。 用正则替换来去掉多余的空格与字符:
1 | $str = 'one two'; |