## 正则表达式
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
正则表达式是由 **普通字符**(例如字符 a 到 z)以及 **元字符** 组成的文字模式。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
### 分隔符
当使用 PCRE 函数的时候,模式需要由分隔符闭合包裹。分隔符可以使任意非字母数字、非反斜线、非空白字符。
经常使用的分隔符是正斜线(/)、hash符号(#) 以及取反符号(~)下面的例子都是使用合法分隔符的模式。
- /foo bar/
- \#^[^0-9]$\#
- +php+
- %[a-zA-Z0-9_-]%
### 元字符
正则表达式的威力源于它可以在模式中拥有选择和重复的能力。 一些字符被赋予特殊的涵义,使其不再单纯的代表自己,模式中的这种有特殊涵义的编码字符称为元字符。
共有两种不同的元字符: 一种是可以在方括号外任何地方使用的,一种是需要在方括号内使用的。
**方括号外使用的元字符:**
| 字符 | 描述 |
| --- | --- |
| \ | 转义字符 |
| ^ | 断言目标的开始位置(或在多行模式下是行首) |
| $ | 断言目标的结束位置(或在多行模式下是行尾) |
| . | 匹配除换行符外的任何字符(默认) |
| [ | 开始字符类定义 |
| ] | 结束字符类定义 |
| \| | 开始一个可选分支 |
| ( | 子组的开始标记 |
| ) | 子组的结束标记 |
| ? | 作为量词,表示 0 次或 1 次匹配。位于量词后面用于改变量词的贪婪特性 |
| * | 量词,0 次或多次匹配 |
| + | 量词,1 次或多次匹配 |
| { | 自定义量词开始标记 |
| } | 自定义量词结束标记 |
**方括号内使用的元字符:**
| 字符 | 描述 |
| --- | --- |
| \ | 转义字符 |
| ^ | 仅在作为第一个字符时,表明字符类取反 |
| - | 标记字符范围 |
**限定符(量词)**
限定符主要是用来限定每个字符串出现的次数。
| 限定字符 | 含义 |
| --- | --- |
| ? | 零次或一次,等价于 {0,1} |
| * | 零次或多次, 等价于 {0,n}|
| + | 一次或多次, 等价于 {1,n} |
| {n} | n 次 |
| {n,} | 至少 n 次 |
| {n,m} | n 到 m 次 |
### 转义序列(反斜线)
表达式中的反斜杠有多重意义,如转义字符、显示非打印的字符、指定预定义的字符集、定义断言。
** (1)转义字符 **
转义字符主要是将一些特殊字符转为普通字符。比如要匹配元字符,就需要在他们前面加上反斜线,例如:\?, \^, \$
** (2)显示非打印字符 **
非打印字符也可以是正则表达式的组成部分,常见的非打印字符转义序列:
| 字符 | 含义 |
| --- | --- |
| \b | 退格 |
| \f | 换页符 |
| \n | 换行符 |
| \r | 回车符 |
| \s | 任何空白字符,包括空格、制表符、换页符等 |
| \S | 任何非空白字符 |
| \t | 制表符 |
| \v | 垂直制表符 |
**后向引用**
后向引用依靠子表达式的 ”记忆” 功能,匹配连续出现的字串或是字符。如:(abc)(123)\1\2,表示匹配字符串 abc123abc123
** (3)指定预定义的字符集 **
| 字符 | 含义 |
| --- | --- |
| \d | 任意十进制数字 |
| \D | 任意非十进制数字 |
| \s | 任意空白字符 |
|\S | 任意非空白字符 |
| \w | 任意单词字符(数字,字母,下划线)|
| \W | 任意非单词字符 |
** (4)定义断言 **
一个断言指定一个必须在特定位置匹配的条件, 它们不会从目标字符串中消耗任何字符。
| 字符 | 含义 |
| --- | --- |
| \b | 单词边界 |
| \B | 非单词边界 |
| \A | 目标的开始位置(独立于多行模式)|
| \z | 目标的结束位置(独立于多行模式)|
| \Z | 目标的结束位置或结束处的换行符(独立于多行模式)|
| \G | 在目标中首次匹配位置 |
### 模式修饰符
模式修饰符的作用是设定模式,也就是正则表达式如何解释。php 中主要模式如下:
| 修饰符 | 说明 |
| --- | --- |
| i | 忽略大小写 |
| m | 多行文本模式 |
| s | 单行文本模式 |
| x | 忽略空白字符 |
### 表达式示例
匹配特殊字符,例如:$foo, [abc], c++
/\$foo/
/\[abc\]/
/c\+\+/
匹配以 face 开头的字符串,例如:facebook
/^face/
匹配以 book 结尾的字符串,例如:facebook
/book$/
表达式将匹配 facebook, gitbook
/(face|git)book/
匹配包含元音的字符串
/[aeiou]/
匹配英文字母和阿拉伯数字
/[a-zA-Z0-9]/
匹配非阿拉伯数字
/[^0-9]/
表达式将匹配 gogle, google, gooogle, goo...ogle
/goo*gle/
/goo{0,}gle/
表达式将匹配 gogle, google
/goo?gle/
/goo{0,1}gle/
表达式将匹配 google,gooogle, goo...ogle
/goo+gle/
/goo{1,}gle/
表达式将匹配 google, gooogle, goooogle
/goo{1,3}gle/
表达式将匹配 gooogle
/goo{2}gle/
表达式将匹配 2017-05-21, 0000-00-00, 1234-56-78
/\d{4}-\d{2}-\d{2}/
匹配一个完整的单词,例如: tom and jerry
/\band\b/
匹配忽略大小写,表达式将匹配 google, Google, GOOGLE
/google/i
### 贪婪匹配与惰性匹配
- 贪婪匹配:就是匹配尽可能多的字符。
- 懒惰匹配:就是匹配尽可能少的字符。
例如使用表达式 `/<div>.*<\/div>/` 匹配字符串 `<div>google</div><div>facebook</div>`
- 贪婪匹配返回: `<div>google</div><div>facebook</div>`
- 懒惰匹配返回: `<div>google</div>`
**注意:** 默认情况下,量词都是 ”贪婪” 的,在量词后面加上?(问号)标记,它就会转换成懒惰匹配。
### PRCE 函数
```
<?php
$html = <<<EOT
{div class="list"}php{/div}
{div class="list"}python{/div}
{div class="list"}java{/div}
EOT;
$pattern = '/{div class="list"}(.*?){\/div}/';
preg_match($pattern, $html, $matches);
print_r($matches);
preg_match_all($pattern, $html, $matches);
print_r($matches);
$str = '小明的出生日期: 1997-10-01';
$pattern = '/(\d{4})-(\d{2})-(\d{2})/i';
$output = preg_replace($pattern, '$1 年 $2 月 $3 日', $str);
echo $output . PHP_EOL;
$output = preg_replace_callback($pattern, function($matches){
return "{$matches[1]} 年 {$matches[2]} 月 {$matches[3]} 日";
}, $str);
echo $output . PHP_EOL;
?>
```
参考链接:
- [模式语法](http://php.net/manual/zh/reference.pcre.pattern.syntax.php)
- [模式修饰符](http://php.net/manual/zh/reference.pcre.pattern.modifiers.php)
- [PCRE函数](http://php.net/manual/zh/ref.pcre.php)
- 基本语法
- PHP标记
- 指令分隔符
- 从HTML中分离
- 注释
- 数据类型
- 布尔值
- 整数
- 浮点数
- 字符串
- 数组
- 对象
- 资源
- 空值
- 变量
- 基础
- 预定义变量
- 变量范围
- 可变变量
- 常量
- 常量语法
- 魔术常量
- 运算符
- 算术运算符
- 赋值运算符
- 位运算符
- 比较运算符
- 递增与递减运算符
- 逻辑运算符
- 字符串运算符
- 数组运算符
- 类型运算符
- 流程控制
- if条件结构
- switch条件结构
- while循环结构
- do-while循环结构
- for循环结构
- foreach循环结构
- 包含文件
- 函数
- 自定义函数
- 可变函数
- 匿名函数
- 递归函数
- 类与对象
- 基本概念
- 属性
- 方法
- 类常量
- 构造函数和析构函数
- 访问控制
- 继承
- 抽象类
- 接口
- Trait
- 重载
- 对象遍历
- 魔术方法
- Final关键字
- 命名空间
- 自动加载
- 错误处理
- 错误显示
- 错误日志
- 错误报告
- 自定义错误处理
- 异常处理
- 异常处理机制
- 扩展异常处理类
- 字符操作
- 数组操作
- 时间操作
- 表单操作
- GET提交
- POST提交
- 文件上传
- 会话控制
- COOKIE操作
- SESSION操作
- 文件操作
- 文件属性
- 读取文件
- 写入文件
- 文件管理
- 文件锁
- 目录处理
- 路径处理
- 网络操作
- HTTP协议
- Socket操作
- CURL操作
- PDO操作
- 介绍
- 连接管理
- 预处理语句
- 事务处理
- 错误处理
- 图像操作
- 正则表达式
- 标准推荐
- 包管理器
- 设计模式
- 常用算法
- 安全防御
- XSS防御
- CSRF防御