# 基础

完整的正则表达式由两种字符组成。特殊字符（**元字符**）和普通字符（文本）。

示例：

```
/^\d+hello.*/
```

* `^  \d   +   .  *` 都是元字符
* `Hello` 是文本字符

## 元字符

常见的元字符

* .            匹配除换行符以外的任意字符
* \w            匹配字母或数字
* \s            匹配任意的空白符
* \d            匹配数字
* \b            匹配单词的开始或结束
* ^            匹配字符串的开始
* $            匹配字符串的结束
* \xxx        查找以八进制数 xxx 规定的字符。
* \xdd       查找以十六进制数 dd 规定的字符。
* \uxxxx    查找以十六进制数 xxxx 规定的 Unicode 字符。

## 字符转义

* tesh.php匹配deerchao.php
* c:\windows匹配c:\windows
* 2\\^8匹配2^8(通常这是2的8次方的书写方式)。

> 思考：
>
> 333333$33\33333
>
> 要匹配上面字符串中的“$”正则应该怎么写？
>
> 如果在PHP中preg\_match函数分别用单引号和双引号的表达式来匹配上面的$,怎么写？
>
> **答案：**
>
> 表达式需要的规则是 $
>
> 用单引号表示上面的字符串 $
>
> 用双引号表示上面的字符串 $
>
> ```php
> <?php
> $uids1='33333\$333\3333';
> preg_match_all("/\\\\\\\$/", $uids1, $matchs);
> print_r ($matchs);
> $uids2='33333\$333\3333';
> preg_match_all('/\\\\\$/i', $uids2, $matchs);
> print_r ($matchs);
> ```

## 多选结构

* Windows98|Windows2000|WindosXP
* ^Windows98|Windows2000|WindowsXP$
* Windows(98|2000|XP)
* 多选结构可以包括很多字符，但不能超越括号的界限。

## 分组

可以用小括号来指定子表达式(也叫做分组)

**ip地址**

`(\d{1,3}\.){3}\d{1,3}` 简单的IP地址匹配表达式，但是它也将匹配256.300.888.999这种不可能存在的IP地址。正确如下

```
((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
```

## 后向引用

使用小括号指定一个子表达式（**分组**）后，匹配这个子表达式的文本可以被**捕获**，从而在表达式或其它程序中作进一步的处理。

默认情况下，每个分组会自动拥有一个组号，规则是：**以分组的左括号为标志，从左向右，第一个分组的组号为1，第二个为2，以此类推。**

示例：

```
\b(\w+)\b\s+\1\b
```

可以用来匹配重复的单词

匹配诸如：where where go, tom tom happy

## 环视（零宽断言）

* 环视不匹配任何字符，只匹配文本中的特定位置。类似于\b,^,$那样。**环视不会占用字符。**
* 环视分为**顺序**和**逆序**两种。

**顺序**

* (?=exp)位置的后面能匹配exp 。例如： (?=\d)当前位置右边是数字。
* (?!exp)位置的后面不能匹配exp 。例如： (?!\d)当前位置右边不是数字。

**逆序**

* (?<=exp)位置的前面能匹配exp。例如： (?<=\d)当前位置左边是数字。
* (?\<!exp)位置的前面不能匹配exp 。例如： (?\<!\d)当前位置左边不是数字。

**示例**

环视为数值添加逗号`5345678986` =》 `5,345,678,986`

**分析：**

我们需要找到一个位置，并将‘位置’替换为‘,’。

这个位置需要符合下面几个条件。

1. 左边必须有数字
2. 右边的数字是3的倍数

```php
<?php
$string = ' 5345678986';
$pattern = '/(?<=\d)(?=(\d\d\d)+$)/';
$replacement = ',';
echo preg_replace($pattern, $replacement, $string);
```

## 贪婪与懒惰（匹配优先与忽略优先）

当正则表达式中包含能接受重复的量词(指定数量的代码，例如+,\*,{3,12}等)时，**通常的行为是匹配尽可能多的字符。**

表达式：a.\*b，它将会匹配最长的以a开始，以b结束的字符串。如果用它来搜索aabab的话，它会匹配整个字符串aabab。这被称为**贪婪匹配。**

我们更需要**懒惰匹配**，也就是匹配尽可能少的字符。前面给出的量词都可以被转化为懒惰匹配模式，**只要在它后面加上一个问号?**。这样.\*?就意味着匹配任意数量的重复，但是在能使整个**匹配成功的前提下使用最少的重复。**

a.\*?b匹配最短的，以a开始，以b结束的字符串。如果把它应用于aabab的话，它会匹配aab和ab。
