增加正则表达式

master
高宏宇 1 month ago
parent a59d7ee612
commit 784247b2ee

@ -14,4 +14,5 @@
- [第十一章](第十一章/01.md)
- 附录
- [HTTP简介](工具/http.md)
- [ASCII码表](工具/ascii.md)
- [ASCII码表](工具/ascii.md)
- [正则表达式](工具/正则表达式.md)

@ -0,0 +1,276 @@
- [1. 正则表达式函数](#1-正则表达式函数)
- [1.1. **匹配类函数**](#11-匹配类函数)
- [1.2. **替换类函数**](#12-替换类函数)
- [1.3. **分割与筛选**](#13-分割与筛选)
- [2. 正则表达式规则](#2-正则表达式规则)
- [2.1. **基础字符匹配**](#21-基础字符匹配)
- [2.2. **量词(控制匹配次数)**](#22-量词控制匹配次数)
- [2.3. **边界控制**](#23-边界控制)
- [2.4. **分组与引用**](#24-分组与引用)
- [2.5. **替代与条件匹配**](#25-替代与条件匹配)
- [2.6. **模式修饰符**](#26-模式修饰符)
- [2.7. **特殊结构**](#27-特殊结构)
- [2.8. **Unicode 支持**](#28-unicode-支持)
- [2.9. **示例**](#29-示例)
- [2.10. **注意事项**](#210-注意事项)
PHP提供了丰富的正则表达式函数主要用于模式匹配、替换、分割等操作。以下是核心函数及其功能详解
# 1. 正则表达式函数
## 1.1. **匹配类函数**
- **`preg_match()`**
执行单次正则匹配返回匹配次数0或1。支持捕获组存储到`$matches`数组。
示例:匹配字符串中的数字
```php
php$text = "Order 12345";
preg_match('/Order \d+/', $text, $matches); // $matches[0] = "Order 12345"
```
- **`preg_match_all()`**
全局匹配,返回所有匹配结果到`$matches`数组。可通过`flags`参数(如`PREG_PATTERN_ORDER`)调整结果排序。
示例提取HTML中的链接
```php
php$html = '<a href="link1.html">Link1</a><a href="link2.html">Link2</a>';
preg_match_all('/<a href="(.*?)">(.*?)<\/a>/', $html, $matches);
// $matches[1] = ["link1.html", "link2.html"], $matches[2] = ["Link1", "Link2"]
```
## 1.2. **替换类函数**
- **`preg_replace()`**
执行正则替换,支持逆向引用(如`$1`)和数组替换。
示例:脱敏手机号
```php
php$text = "用户电话:123-4567-8901";
$masked = preg_replace('/(\d{3})-(\d{4})-\d{4}/', '$1-****-$2', $text);
// 输出 "用户电话:123-****-4567"
```
- **`preg_replace_callback()`**
通过回调函数动态生成替换内容,灵活性更高。
示例:年份递增
```php
php$text = "April fools day is 04/01/2002";
echo preg_replace_callback(
"|(\d{2}/\d{2}/)(\d{4})|",
function($m) { return $m[1] . ($m[2] + 1); },
$text
); // 输出 "04/01/2003"
```
- **`preg_filter()`**
类似`preg_replace`,但仅保留有替换结果的条目(忽略未匹配项)。
## 1.3. **分割与筛选**
- **`preg_split()`**
按正则规则分割字符串,返回数组。支持`limit`限制分割次数,`flags`调整结果格式(如`PREG_SPLIT_NO_EMPTY`过滤空项)。
示例分割CSV
```php
php$csv = "apple, orange; banana|pear";
$fruits = preg_split('/[,;|]/', $csv); // ["apple", "orange", "banana", "pear"]
```
- **`preg_grep()`**
筛选数组中匹配模式的元素。
示例:筛选有效邮箱
```php
php$emails = ["test@qq.com", "invalid-email", "user@example.com"];
$valid = preg_grep('/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/', $emails);
// 输出 ["test@qq.com", "user@example.com"]
```
# 2. 正则表达式规则
PHP 的正则表达式基于 **PCREPerl Compatible Regular Expressions** 库,其匹配规则与 Perl 正则高度兼容。以下是 PHP 正则表达式的核心匹配规则,涵盖字符匹配、量词、边界控制、分组等关键功能:
------
## 2.1. **基础字符匹配**
- **普通字符**:直接匹配对应字符(如 `a` 匹配字母 `a`)。
- **元字符**:需转义后匹配(如 `\.` 匹配点号 `.``\*` 匹配星号 `*`)。
```php
php
preg_match('/\.com/', 'example.com'); // 匹配 ".com"
```
- **特殊字符类**
- `\d`:匹配数字(等价于 `[0-9]`)。
- `\w`:匹配单词字符(字母、数字、下划线,等价于 `[a-zA-Z0-9_]`)。
- `\s`:匹配空白字符(空格、制表符、换行等)。
- 反义类:`\D`(非数字)、`\W`(非单词字符)、`\S`(非空白)。
------
## 2.2. **量词(控制匹配次数)**
| 量词 | 含义 | 示例 |
| ------- | ---------------------------- | --------------------------------- |
| `.` | 匹配单个任意字符(除换行符) | `a.b` 匹配 `aXb`、`a b` 等 |
| `*` | 匹配 0 次或多次 | `a*` 匹配 `""`, `a`, `aa` |
| `+` | 匹配 1 次或多次 | `a+` 匹配 `a`, `aa` |
| `?` | 匹配 0 次或 1 次 | `a?` 匹配 `""``a` |
| `{n}` | 精确匹配 n 次 | `a{3}` 匹配 `aaa` |
| `{n,}` | 匹配至少 n 次 | `a{2,}` 匹配 `aa`, `aaa` |
| `{n,m}` | 匹配 n 到 m 次 | `a{2,4}` 匹配 `aa`, `aaa`, `aaaa` |
**贪婪 vs 非贪婪**
- 默认贪婪模式(匹配尽可能多的字符),如 `.*` 会匹配整个字符串。
- 非贪婪模式(在量词后加 `?`),如 `.*?` 匹配最短可能。
```php
php$text = "<div>content</div>";
preg_match('/<div>(.*?)<\/div>/', $text, $matches); // $matches[1] = "content"
```
------
## 2.3. **边界控制**
- **锚点**
- `^`:匹配字符串开头(多行模式下匹配行首)。
- `$`:匹配字符串结尾(多行模式下匹配行尾)。
```php
phppreg_match('/^Hello/', 'Hello world'); // 匹配成功
preg_match('/world$/', 'Hello world'); // 匹配成功
```
- **单词边界**
- `\b`:匹配单词边界(如 `\bword\b` 匹配独立单词 `word`)。
- `\B`:匹配非单词边界;可以认为是 `\b`的反义。
```php
phppreg_match('/\bcat\b/', 'The cat sat'); // 匹配 "cat"
preg_match('/\bcat\b/', 'category'); // 不匹配
```
------
## 2.4. **分组与引用**
- **捕获组**:用 `( )` 包裹,匹配内容会被捕获到 `$matches` 数组。
```php
phppreg_match('/(\d{4})-(\d{2})/', '2023-05', $matches);
// $matches[0] = "2023-05", $matches[1] = "2023", $matches[2] = "05"
```
- **非捕获组**:用 `(?: )` 包裹,不捕获内容(提升性能)。
```php
phppreg_match('/(?:\d{3})-(\d{4})/', '123-4567', $matches);
// $matches[1] = "4567"(仅捕获第二组)
```
- **反向引用**:用 `\n`n 为组号)引用已捕获的内容。
```php
php
preg_match('/(\w+)\s\1/', 'test test', $matches); // 匹配重复单词
```
------
## 2.5. **替代与条件匹配**
- **分支匹配**:用 `|` 表示“或”关系。
```php
php
preg_match('/(cat|dog)/', 'I have a cat'); // 匹配 "cat"
```
- **条件匹配**PCRE 支持 `(?(condition)yes|no)` 语法(较少用)。
------
## 2.6. **模式修饰符**
修饰符放在定界符后(如 `/pattern/i`),常用如下:
| 修饰符 | 含义 | 示例 |
| ------ | ---------------------------------- | ---------------------------- |
| `i` | 不区分大小写 | `/hello/i` 匹配 `Hello` |
| `m` | 多行模式(`^` 和 `$` 匹配行首/尾) | `/^line/m` 匹配每行开头 |
| `s` | 让 `.` 匹配换行符 | `/.*./s` 匹配跨行文本 |
| `u` | 支持 UTF-8 编码 | `/\p{L}/u` 匹配 Unicode 字母 |
| `x` | 忽略模式中的空白和注释 | `/a b /x` 匹配 `ab` |
------
## 2.7. **特殊结构**
- **环视Lookaround**
- 正向环视:`(?=pattern)`(后面必须跟 `pattern``(?!pattern)`(后面不能跟 `pattern`)。
- 反向环视:`(?<=pattern)`(前面必须是 `pattern``(?<!pattern)`(前面不能是 `pattern`)。
```php
php
preg_match('/(?<=\d)abc/', '123abc'); // 匹配 "abc"(前面是数字)
```
- **原子组**`(?>pattern)` 防止回溯(性能优化)。
------
## 2.8. **Unicode 支持**
- 使用 `\p{L}` 匹配任意字母,`\p{N}` 匹配数字,需配合 `u` 修饰符。后一个`/`后面可以有模式修饰符`i``m``s``u``x`等。
```php
php
preg_match('/\p{L}+/u', '中文'); // 匹配 "中文"
```
------
## 2.9. **示例**
模式匹配字符串的开始和结束一般是`/`PHP可以有其他的替代具体请参考手册
```php
php// 匹配邮箱
$email = "user@example.com";
if (preg_match('/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/', $email)) {
echo "Valid email";
}
// 提取日期YYYY-MM-DD
$text = "Today is 2023-05-20";
preg_match('/\b(\d{4})-(\d{2})-(\d{2})\b/', $text, $matches);
// $matches[1] = "2023", $matches[2] = "05", $matches[3] = "20"
```
------
## 2.10. **注意事项**
1. **转义字符**:在双引号字符串中,`\` 可能被转义,建议用单引号或额外转义。
2. **性能**:避免过度使用嵌套分组或回溯复杂的模式。
3. **错误处理**:检查 `preg_last_error()` 调试复杂正则。
PHP 正则表达式功能强大,合理使用可高效处理字符串匹配、验证和提取任务。

@ -326,7 +326,7 @@ http://localhost/2020CodeAudit/c8/8-6-pregrematch-1.php
## 6.2. 特殊字符未转义
在正则表达式里,所有能被正则表达式引擎解析的字符都算是特殊字符,而在匹配这些字符的原字符时需要使用反斜杠(\)来进行转义,如果不进行转义,像样英文句号(.)则可用来表示任何字符,存在安全隐患
在正则表达式里,所有能被正则表达式引擎解析的字符都算是特殊字符,而在匹配这些字符的原字符时需要使用反斜杠(\\\)来进行转义,如果不进行转义,像样英文句号(.)则可用来表示任何字符,存在安全隐患
```php
<?php

Loading…
Cancel
Save