正则基础总结

本文于 2802 天之前发表,文中内容可能已经过时。

无论哪种语言都会有正则的使用,以前都没有总结一下使用,这里记录一下
正则需要多用多练,因为有些特殊的字符经常不去使用的话就需要去查看了。

1.转义字符

转义字符在正则中会有很多的使用,所以首先记录一下常用的转移字符

  • \n 换行
  • \r 回车
  • \t table跳转

\r : return 到当前行的最左边。
\n: newline 向下移动一行,并不移动左右。
Linux中\n表示回车+换行;
Windows中\r\n表示回车+换行。
Mac中\r表示回车+换行。

2.定界符

不要使用\当作定界符,一般使用像~~、!!、##等,建议使用# # 比较好用

3.原子

原子是匹配模式中最基础的组成部分,每个模式至少包含一个原子

  • 普通原子 可见原子 a-z、A-Z、0-9;不可见原子\n、\r、\t、\v、\f
  • 特殊字符 $(){[|.^*+?
  • 通用字符类
    • \d 任意十进制数字,等价于[0-9]
    • \D 任意非十进制数字,等价于[^0-9]
    • \w 任意单词字符,等价于[a-zA-Z0-9_]
    • \W 任意非单词字符,等价于[^a-zA-Z0-9_]
    • \s 匹配任意空白字符,等价于[ \f\n\r\t\v]
    • \S 匹配任意非空白字符,等价于[^ \f\n\r\t\v]
  • 自定义原子表作为原子 #[aeiou]#

4.元字符

  1. * 匹配0次1次或多次其前的原子,等价于{0,}
  2. + 匹配一次或多次其前的原子,等价于{1,}
  3. ? 匹配0次或1次其前的原子,等价于{0,1}
  4. . 匹配除了换行符以外的任意一个字符
  5. | 匹配两个或多个分支选择
  6. {n} 表示其前面的原子恰好出现n次
  7. {n,} 表示其前的原子出现不小于n次,即大于等于n次
  8. {n,m} 表示其前的原子至少出现n次,最多出现m次
  9. ^或\A 匹配输入字符的开始的位置(或在多行模式下行的开头,即紧随一个换行符之后) 规定字符必须出现在开头
  10. $或\Z 匹配输入字符串的结束位置(活在多行模式下行的结尾,即紧随一个换行符之前) 规定字符必须出现在结尾
  11. \b 匹配单词的边界
  12. \B 匹配单词的边界以外的部分
  13. [] 匹配方括号中的任意一个原子
  14. [^] 匹配除了方括号中的原子以外的任意一个字符
  15. () 匹配其整体为一个原子,即模式单元。可以被后面的回调使用

5.模式修饰符

  1. i 忽略大小写
  2. m 多行模式,将字符串视为多行。默认的正则开始“^”和结束“$”将目标字符串作为单一的一“行”字符。加上m后,那么开始和结束将会指字符串的每一行
  3. s 模式中的点号元字符匹配所有字符,包含换行符。如果没有这个 修饰符,点号不匹配换行符
  4. x 将模式中的空白忽略
  5. U 非贪婪,即懒惰匹配
  6. D 模式中的$仅匹配目标字符串的结尾。没有此选项时,如果最后一个字符是换行符的话,$也会匹配此字符之前。如果设定了 m 修正符则忽略此选项
  7. e 只用在preg_replace()函数中,在替换字符串中对逆向引用做正常的替换,将其作为 PHP 代码求值,并用其结果来替换所搜索的字符串
  8. u 此修正符打开一个与 perl 不兼容的附加功能。 模式字符串被认为是utf-8的.

6.正则表达式运算符优先级

正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似

7.php常用正则函数

1
2
3
4
preg_match(); //匹配一次
preg_match_all(); //全部匹配
preg_replace(); //替换
preg_replace_callback();

8.常用正则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/<\s*(\S+)(\s[^>]*)?>[\s\S]*<\s*\/\1\s*>/	html标记
~<a[^>]*href=\"(?<link>[^>]*)\"[^>]*>(?<title>.*)</a>~ 超链接
/\n[\s| ]*\r/ 空行
/\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/ 邮箱
/[a-zA-z]+://(\w+(-\w+)*)(\.(?:\w+(-\w+)*))*(\?\S*)?/ 网址
/[\x{4e00}-\x{9fa5}]/u 中文
(\d{4}|\d{2})-((1[0-2])|(0?[1-9]))-(([12][0-9])|(3[01])|(0?[1-9])) 年-月-日
((1[0-2])|(0?[1-9]))/(([12][0-9])|(3[01])|(0?[1-9]))/(\d{4}|\d{2}) 年/月/日
/([01]?\d|2[0-3]):[0-5]?\d:[0-5]?\d/ 时:分:秒
(\d{1,3}\.){3}\d{1,3} IP
/\d{15}|\d{17}[0-9Xx]/ 身份证
/[1-9]\d*/ 正整数
/-[1-9]\d*/ 负整数
/(13\d|14[57]|15[^4,\D]|17[678]|18\d)\d{8}|170[059]\d{7}/ 手机号
(\d{4}-|\d{3}-)?(\d{8}|\d{7}) 电话号码

9.php过滤函数

以往,对于常见的SQL注入等漏洞,采取的方式一般都是对数据进行过滤,而对GET/GET/_POST/COOKIE/COOKIE/_SERVER等全局数组变量的直接使用是不够安全的,故PHP 5.2.0版本以后,推出Filter系列函数,对外部脚本的数据进行过滤,比如POST表单中的email邮箱进行验证,则将$filter参数设置为FILTER_VALIDATE_EMAIL即可。

1
2
3
4
5
mixed filter_input(int $type , string $variable [, int $filter = FILTER_DEFAULT [,mixed $options]]);
type 必需。规定输入类型。INPUT_GET、INPUT_POST、INPUT_COOKIE、INPUT_ENV、INPUT_SERVER;
variable 必需。规定要过滤的变量。
filter 可选。规定要使用的过滤器的ID。默认是FILTER_DEFAULT。过滤器ID可以是ID名称(比如FILTER_VALIDATE_EMAIL),或ID号(比如 274)。
options 可选。规定包含标志/选项的数组。检查每个过滤器可能的标志和选项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Without this function...
<?php
if (!isset($_GET['a'])) {
$a = null;
} elseif (!is_string($_GET['a'])) {
$a = false;
} else {
$a = $_GET['a'];
}
$b = isset($_GET['b']) && is_string($_GET['b']) ? $_GET['b'] : '';
?>

With this function...
<?php
$a = filter_input(INPUT_GET, 'a');
$b = (string)filter_input(INPUT_GET, 'b');
?>

10.正则的优化

  1. 使用字符组代替分支条件
  2. 优先选择最左端的匹配结果
  3. 标准量词是匹配优先的
  4. 谨慎用点号,尽可能不用*和+这样的任意量词
  5. 能用字符串函数处理的就尽量使用字符串函数处理
  6. 合理使用括号
  7. 能确定起始和结束位置尽量使用^和$
  8. 可以对比较大的正则表达式进行拆分匹配
  9. 使用其它方式代替正则 (PHP中的字符串函数,PHP中的URL函数包括http函数,PHP中的Filter函数)