3-3 元字符与转义

正则表达式中具有特殊含义的字符称之为元字符,常用的元字符有:

\ —- 一般用语转义字符
^ —- 断言目标的开始位置(或在多行模式下是行首)
$ —- 断言目标的结束位置(或在多行模式下是行尾)
. —-匹配除换行符外的任何字符(默认)
[ —- 开始字符类定义
] —- 结束字符类定义
| —- 开始一个可选分支
( —- 子组的开始标记
) —- 子组的结束标记
? —- 作为量词,表示 0 次或 1 次匹配。位于量词后面用于改变量词的贪婪特性。(查阅量词)
* —- 量词,0次或多次匹配
+ —- 量词,1次或多次匹配
{ —- 自定义量词开始标记
} —- 自定义量词结束标记

  1. // 下面的 \s 匹配任意的空白符,包括空格,制表符,换行符。
  2. // [^\s] 代表非空白符。
  3. // [^\s]+ 表示一次或多次匹配非空白符。
  4. $p = '/^我[^\s]+(苹果|香蕉)$/';
  5. $str = '我喜欢吃苹果';
  6. if(preg_match($p, $str)){
  7. echo '匹配成功';
  8. }

元字符具有分为两种,一种是可以在任何地方使用,另一种是只能在方括号内使用,在方括号内使用的有:
\ —- 转义字符
^ —- 仅在作为第一个字符(方括号内)时,表示字符类取反
- —- 标记字符范围

其中 ^ 在方括号外面,表示断言目标的开始位置,但在方括号内部则表示字符类取反,方括号内的减号 - 可以标记字符范围,例如0-9,表示0-9之间的所有数字。

  1. // 下面的 \w 匹配字母或数字或下划线。
  2. $p = '/[\w\.\-]+@[a-z0-9\-]+\.(com|cn)/';
  3. $str = "我的邮箱是Spark.eric@imooc.com";
  4. preg_match($p, $str, $match);
  5. echo $match[0];

3-4 贪婪模式与懒惰模式

正则表达式中每个元字符匹配一个字符,当使用 + 之后将会变得贪婪,它将匹配尽可能多的字符,但是用 ? 字符时,它将尽可能少的匹配字符,即懒惰模式。

贪婪模式:在可匹配与可不匹配的时候,优先匹配

  1. // 下面的 \d 表示匹配数字
  2. $p = '/\d+\-\d+/';
  3. $str = "我的电话是010-12345678";
  4. preg_match($p, $str, $match);
  5. echo $match[0]; // 结果为: 010-12345678

懒惰模式:在可匹配与可不匹配的时候,优先不匹配

  1. $p = '/\d?\-\d?/';
  2. $str = "我的电话是010-12345678";
  3. preg_match($p, $str, $match);
  4. echo $match[0]; // 结果为:0-1

当我们确切的知道所匹配的字符长度的时候,可以使用 {} 指定匹配字符数

  1. $p = '/\d{3}\-\d{8}/';
  2. $str = "我的电话是010-12345678";
  3. preg_match($p, $str, $match);
  4. echo $match[0]; // 结果为: 010-12345678
  1. <?php
  2. //请修改变量p的正则表达式,使他能够匹配str中的姓名
  3. $p = '/name:([\w\s]+)/';
  4. $str = "name:steven jobs";
  5. preg_match($p, $str, $match);
  6. echo $match[1]; //结果为:steven jobs

3-5 使用正则表达式进行匹配

使用正则表达式的目的是为了实现比字符串处理函数更加灵活的处理方式,因此跟字符串处理函数一样,其主要用来判断子字符串是否存在、字符串替换、分割字符串、获取模式子串等。

PHP使用 PCRE 库函数来进行正则处理,通过设定好模式,然后调用相关的处理函数来取得匹配结果。

preg_match 用来执行一个匹配,可以简单的用来判断模式是否匹配成功,或者取得一个匹配结果,他的返回值是匹配成功的次数 0 或者 1,在匹配到 1 次以后就会停止搜索。

  1. $subject = "abcdef";
  2. $pattern = '/def/';
  3. perg_match($pattern, $subject, $matches);
  4. print_r($matches); //结果为: Array( [0] => def )

上面的代码简单的执行了一个匹配,简单的判断 def 是否能匹配成功,但是正则表达式强大的地方是进行模式匹配,因此更多的时候,会使用模式:

  1. $subject = "abcdef";
  2. $pattern = '/a(.*?)d/';
  3. preg_match($pattern, $subject, $matches);
  4. print_r($matches); // 结果为: Array( [0] => abcd [1] => bc )

通过正则表达式可以匹配一个模式,得到更多的有用数据。

  1. <?php
  2. $subject = "my email is spark@imooc.com";
  3. //在这里补充代码,实现正则匹配,并输出邮箱地址
  4. $pattern = '/\w+@\w+.\w+/';
  5. preg_match($pattern, $subject, $match);
  6. print_r($match[0]);

3-6 查找所有匹配结果

preg_match 只能匹配一次结果,但很多时候我们需要匹配所有的记过,preg_match_all 可以循环获取一个列表的所有匹配结果数组。

  1. $p = "|<[^>]+>(.*?)</[^>]+>|i";
  2. $str = "<b>example: <b><div align=left>this is a test</div>";
  3. preg_match_all($p, $str, $matches);
  4. print_r($matches);

可以使用 preg_match_all 匹配一个表格中的数据:

  1. $p = "/<tr><td>(.*?)<\/td>\s*<td>(.*?)<\/td>\s*<\/tr>/i";
  2. $str = '<table> <tr><td>Eric</td><td>25</td></tr> <tr><td>John</td><td>26</td></tr></table>';
  3. preg_match_all($p, $str,$matches);
  4. print_r($matches);
  1. $str = "<ul>
  2. <li>item 1</li>
  3. <li>item 2</li>
  4. </ul>";
  5. //在这里补充代码,实现正则匹配所有li中的数据
  6. $p = '/<li>(.*)<\/li>/';
  7. preg_match_all($p, $str, $matches);
  8. print_r($matches[1]);

3-7 正则表达式的搜索和替换

正则表达式的搜索与替换在某些方面具有重要用途,比图调整目标字符串的格式,改变目标字符串中匹配字符串的顺序等。

例如我们可以简单的调整字符串的日期格式:

  1. $string = 'April 15, 2014';
  2. $pattern = '/(\w+) (\d+), (\d+)/i';
  3. $replacement = '$3, ${1} $2';
  4. echo preg_replace($pattern, $replacement, $string); // 结果为:2014, April 15

其中 ${1} 与 $1 的写法是等效的,表示第一个匹配的子串, $2 代表第二个匹配的。

通过复杂的模式,我们可以更加精确的替换目标字符串的内容。

  1. $patterns = array(
  2. '/(19|20)(\d{2})-(\d{1,2})-(\d{1,2})/',
  3. '/^\s*{(\w+)}\s*=/'
  4. );
  5. $replace = array('\3/\4/\1\2','$\1 ='); //\3等效于$3,\4等效于$4,以此类推
  6. echo preg_replace($patterns, $replace, '{starDate} = 1999-5-27');
  7. // 结果为: $starDate = 5/27/1999
  8. // 详细解释下结果:(19|20)表示取19或者20中的一个数字,(\d{2})表示两个数字,
  9. // (\d{1,2})表示1个或2个数字。^\s*{(\w+)}\s*= 表示以任意空格开头的,并且包含在{}中的字符,并且以任意空格结尾的,最后有个=的。

用正则表达式去掉多余的空格与字符:

  1. $str = 'one two';
  2. $str = preg_replace('/\s+/', '', $str);
  3. echo $str; // 结果变为 'one two'

将目标字符串$str中的文件名替换后增加 em 标签,例如 index.php 要被替换为 index.php

  1. $str = '主要有以下几个文件:index.php, style.css, common.js';
  2. //将目标字符串$str中的文件名替换后增加em标签
  3. $pattern = '/\w+\.\w+/i';
  4. $replacement = '<em>$0</em>';
  5. $str = preg_replace($pattern, $replacement,$str);

3-8 正则匹配常用案例

正则匹配常用在表单验证上,一些字段会有一定的格式要求,比如用户名一般都要求必须是字母、数字或下划线组成,邮箱、电话等也都有自己的规则,因此使用正则表达式可以很好的对这些字段进行验证。实例如下:

  1. $user = array(
  2. 'name' => 'spark1985',
  3. 'email' => 'spark@imooc.com',
  4. 'mobile' => '13312345678'
  5. );
  6. // 进行一般性验证
  7. if(empty($user){
  8. die('用户信息不能为空');
  9. }
  10. if(strlen($user['name']) < 6){
  11. die('用户名长度最少为6位');
  12. }
  13. // 用户名必须为字母,数字与下划线
  14. if(preg_match('/^\w+$/i',$user['name'])){
  15. die('用户名不合法');
  16. }
  17. // 验证邮箱格式是否正确
  18. if(preg_match('/^[\w\.]+@\w+\.\w+$/', $user['email'])){
  19. die('邮箱不合法');
  20. }
  21. // 手机号必须为 11 位数字,且为 1 开头
  22. if(preg_match('/^1\d{10}$/i', $user['mobile'])){
  23. die('手机号不合法');
  24. }
  25. echo '用户信息验证成功';
  26. // 匹配中英文且长度限制在 1,10
  27. $input = "teststr中国心";
  28. preg_match("/^[\x{4e00}-\x{9fa5}a-zA-Z]{1,10}+$/u", $input);