一、简介

1. 什么是正则表达式

正则表达式(Regular Expression)就是用某种模式去匹配一类字符串的一种公式。
正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。
正则表达式是繁琐的,但它是强大的,学会之后的应用会让你除了提高效率外,会给你带来绝对的成就感。只要认真阅读本教程,加上应用的时候进行一定的参考,掌握正则表达式不是问题。
许多程序设计语言都支持利用正则表达式进行字符串操作。

2. 正则表达式的作用

分割,查找,匹配,替换字符串

3. PHP中的正则表达式

在PHP中有两套正则表达式函数库,两者功能相似,只是执行效率略有差异:

一套是由 PCRE(Perl Compatible Regular Expression) 库提供的。使用“preg_”为前缀命名的函数;
一套由 POSIX(Portable Operating System Interface of Unix)扩展提供的。使用以“ereg_”为前缀命名的函数;

PCRE来源于Perl语言,而Perl是对字符串操作功能最强大的语言之一,PHP的最初版本就是由Perl开发的产品。
PCRE语法支持更多特性,比POSIX语法更强大。因此,本文主要介绍 PCRE 语法的正则表达式

4. 正则表达式的组成

在PHP中,一个正则表达式分为三个部分:分隔符、表达式和模式修饰符。

分隔符

分隔符可以使用除字母、数字、反斜线(\)和空白字符之外的任意 ascii 字符。
最常用的分隔符有正斜线(/)、hash符号(#) 以及取反符号(~)。

表达式

有一些特殊字符和非特殊的字符串组成。是决定正则表达式匹配规则的主要部分。

模式修饰符

用于开启和关闭某些特定的功能/模式。

二、分隔符

1. 分隔符的选择

当使用 PCRE 函数的时候,正则表达式必须由分隔符闭合包裹。
分隔符可以使用除字母、数字、反斜线(\)和空白字符之外的任意 ascii 字符。
最常用的分隔符有正斜线(/)、hash符号(#) 以及取反符号(~)。


/foo bar/ (合法)
#^[^0-9]$# (合法)
+php+ (合法)
%[a-zA-Z0-9_-]% (合法)

#[a-zA-Z0-9_-]/ (非法,两边的分隔符不同)
a[a-zA-Z0-9_-]a (非法,分隔符不能是字母)
\[a-zA-Z0-9_-]\ (非法,分隔符不能是反斜线(`\`))

除了上面提到的分隔符,也可以使用括号样式的分隔符,左括号和右括号分别作为开始和结束 分隔符。


{this is a pattern}

2. 分隔符的使用

如果分隔符 在正则表达式中使用,它必须使用反斜线(\)进行转义。
果分隔符经常在正则表达式内出现, 最好使用其他分隔符来提高可读性。


/http:\/\//
#http://#

需要将一个字符串放入正则表达式中使用时,可以用 preg_quote() 函数对其进行转义。 它的第二个参数(可选)可以用于指定需要被转义的分隔符。

//在这个例子中,preg_quote($word) 用于保持星号和正斜杠(/)原文涵义,使其不使用正则表达式中的特殊语义。
$textBody = "This book is */very/* difficult to find.";
$word = "*/very/*";
$reg = "/" . preg_quote($word, '/') . "/"; echo $reg; // 输出 '/\*\/very\/\*/' echo preg_replace ($reg, "<i>" . $word . "</i>", $textBody); // 输出 'This book is <i>*/very/*</i> difficult to find.'

可以在结束分隔符后面增加模式修饰符来影响匹配效果。
下面的例子是一个大小写不敏感的匹配


#[a-z]#i

三、元字符

1. 转义符

字符 描述
\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个 向后引用。
例如,'n' 匹配字符 "n"。'n' 匹配一个换行符。序列 '\' 匹配 "" 而 "(" 则匹配 "("。

2. 定位符

字符 描述
^ 匹配输入字符串的开始位置 (或在多行模式下是行首)
$ 匹配输入字符串的结束位置 (或在多行模式下是行尾)
\b 匹配一个单词边界,即字与空格间的位置
\B 非单词边界匹配

3. 限定符

字符 描述
* 匹配前面的子表达式零次或多次。
例如,zo 能匹配 "z" 以及 "zoo"。 等价于{0,}。
+ 匹配前面的子表达式一次或多次。
例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
? 当该字符作为量词,表示匹配前面的子表达式零次或一次。
例如,"do(es)?" 可以匹配 "do" 或 "does" 。? 等价于 {0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。
例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。
例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。
例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。

4. 通用字符

字符 描述
\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]
. 匹配除换行符(n、r)之外的任何单个字符。
要匹配包括 'n' 在内的任何字符,请使用像"(.
n)"的正则表达式。

5. 非打印字符

字符 描述
\n 匹配一个换行符。等价于 x0a 和 cJ。
\r 匹配一个回车符。等价于 x0d 和 cM。
\t 匹配一个制表符。等价于 x09 和 cI。

6. 多选分支符

字符 描述
| 竖线字符 | 可以匹配多选一的情况。
例如,'z|food' 能匹配 "z" 或 "food"。'(z|f|g)ood' 则匹配 "zood"、"food"或 "good"。

7. 字符组

字符 描述
[x|y] 匹配 x 或 y。
例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 则匹配 "zood" 或 "food"。
[xyz] 字符集合。匹配所包含的任意一个字符。
例如, [abc] 可以匹配 "plain" 中的 'a'。
[^xyz] 负值字符集合。匹配未包含的任意字符。
例如, [^abc] 可以匹配 "plain" 中的'p'、'l'、'i'、'n'。
[a-z] 字符范围。匹配指定范围内的任意字符。
例如,[a-z] 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。
[^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。
例如,[^a-z] 可以匹配任何不在 'a' 到 'z' 范围内的任意字符。

8. 非贪婪匹配符

字符 描述
? 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。
非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。
例如,对于字符串 "oooo",'o+?' 将匹配单个 "o",而 'o+' 将匹配所有 'o'。

9. ( )分组

字符 描述
(pattern) 匹配 pattern 并获取这一匹配。要匹配圆括号字符,请使用 \(\)
(?:pattern) 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个正则表达式的各个部分是很有用。
例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。
(?=pattern) 正向肯定预查(look ahead positive assert),在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。
例如,"Windows(?=95|98|NT|2000)"能匹配"Windows2000"中的"Windows",但不能匹配"Windows3.1"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern) 正向否定预查(negative assert),在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。
例如"Windows(?!95|98|NT|2000)"能匹配"Windows3.1"中的"Windows",但不能匹配"Windows2000"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?<=pattern) 反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反。
例如,"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。
(?<!pattern) 反向否定预查,与正向否定预查类似,只是方向相反。
例如"(?<!95|98|NT|2000)Windows"能匹配"3.1Windows"中的"Windows",但不能匹配"2000Windows"中的"Windows"。

四、模式修饰符

1. i(不区分大小写)

如果设置了这个修饰符,正则表达式中的字母会进行大小写不敏感匹配。

2. m(多行模式)

默认情况下,PCRE 认为目标字符串是由单行字符组成的(然而实际上它可能会包含多行)。
"行首"元字符 (^) 仅匹配字符串的开始位置, 而"行末"元字符 ($) 仅匹配字符串末尾, 或者最后的换行符(除非设置了 D 修饰符)。

当这个修饰符设置之后,“行首”元字符 (^) 和“行末”元字符 ($) 就会匹配目标字符串中任意换行符之前或之后,另外,还分别匹配目标字符串的最开始和最末尾位置。

如果目标字符串 中没有 "n" 字符,或者正则表达式中没有出现 ^$,设置这个修饰符不产生任何影响。

3. s(点号通配模式)

默认情况下,点号(.)不匹配换行符。
如果设置了这个修饰符,正则表达式中的点号元字符匹配所有字符,包含换行符。

4. U(贪婪模式)

这个修饰符与前面提到的 ? 作用相同,使正则表达式默认为非贪婪匹配,通过量词后紧跟 ? 的方式可以使其转为贪婪匹配。

在非贪婪模式,通常不能匹配超过 pcre.backtrack_limit 的字符。

贪婪模式

$str = '&lt;b&gt;abc&lt;/b&gt;&lt;b&gt;def&lt;/b&gt;';
$pattern = '/&lt;b&gt;.*&lt;/b&gt;/';
preg_replace($pattern, '\\1', $str);

.*会匹配 abc</b><b>def

非贪婪模式

方法一、使用 ? 转为非贪婪模式

$str = '&lt;b&gt;abc&lt;/b&gt;&lt;b&gt;def&lt;/b&gt;';
$pattern = '/&lt;b&gt;.*?&lt;/b&gt;/';
preg_replace($pattern, '\\1', $str);

.*会分别匹配 abcdef

方法二、使用修饰符 U 转为非贪婪模式

$str = '&lt;b&gt;abc&lt;/b&gt;&lt;b&gt;def&lt;/b&gt;';
$pattern = '/&lt;b&gt;.*&lt;/b&gt;/U';
preg_replace($pattern, '\\1', $str);

5. u(支持UTF-8转义表达)

此修正符使正则表达式和目标字符串都被认为是 utf-8 编码。
无效的目标字符串会导致 preg_* 函数什么都匹配不到;无效的正则表达式字符串会导致 E_WARNING 级别的错误。


$str = '中文'; $pattern = '/^[\x{4e00}-\x{9fa5}]+$/u'; if (preg_match($pattern, $str)) {
echo '该字符串全是中文';
} else {
echo '该字符串不全是中文';
}

6. D(结尾限制)

默认情况下,如果使用 $ 限制结尾字符,当字符串以一个换行符结尾时, $符号还会匹配该换行符(但不会匹配之前的任何换行符)。
如果设置这个修饰符,正则表达式中的 $ 符号仅匹配目标字符串的末尾。
如果设置了修饰符 m,这个修饰符被忽略。

7. x

如果设置了这个修饰符,正则表达式中的没有经过转义的或不在字符类中的空白数据字符总会被忽略, 并且位于一个未转义的字符类外部的#字符和下一个换行符之间的字符也被忽略。

8. A

如果设置了这个修饰符,正则表达式被强制为"锚定"模式,也就是说约束匹配使其仅从 目标字符串的开始位置搜索。

9. S

当一个正则表达式需要多次使用的时候,为了得到匹配速度的提升,值得花费一些时间对其进行一些额外的分析。
如果设置了这个修饰符,这个额外的分析就会执行。
当前,这种对一个正则表达式的分析仅仅适用于非锚定模式的匹配(即没有单独的固定开始字符)。

五、反向引用

使用 ( ) 标记的开始和结束的多个原子,不仅是一个独立的单元,也是一个子表达式。
在一个 ( ) 中的子表达式外面,反斜线紧跟一个大于 0 的数字,就是对之前出现的某个子表达式的后向引用。
后向引用用于重复搜索前面某个 ( ) 中的子表达式匹配的文本。

1. 在正则表达式中使用反向引用

(sens|respons)e and \1ibility 将会匹配 ”sense and sensibility” 和 ”response and responsibility”, 而不会匹配 ”sense and responsibility”

2. 在PCRE函数中使用反向引用


&lt;?php
$str = '&lt;b&gt;abc&lt;/b&gt;&lt;b&gt;def&lt;/b&gt;';
$pattern = '/&lt;b&gt;(.*)&lt;\/b&gt;&lt;b&gt;(.*)&lt;\/b&gt;/';
$replace = preg_replace($pattern, '\\1', $str);
echo $replace . "\n"; $replace = preg_replace($pattern, '\\2', $str);
echo $replace . "\n";

输出:


abc
def

六、正则表达式常用PCRE函数

PHP官网的讲解已经很详细了,这里不再做多余的论述

执行正则表达式匹配 preg_match()

执行正则表达式全局匹配 preg_match_all()

执行一个正则表达式的搜索和替换 preg_replace()

执行一个正则表达式搜索并且使用一个回调进行替换 preg_replace_callback()

执行多个正则表达式搜索并且使用对应回调进行替换 preg_replace_callback_array()

通过一个正则表达式分隔字符串 preg_split()

七、应用实践

1. 正则表达式匹配中文

UTF-8汉字编码范围是 0x4e00-0x9fa5
在ANSI(GB2312)环境下,0xb0-0xf70xa1-0xfe

UTF-8要使用 u模式修正符 使模式字符串被当成 UTF-8
在ANSI(GB2312)环境下,要使用chr将Ascii码转换为字符

UTF-8


&lt;?php $str = '中文'; $pattern = '/[\x{4e00}-\x{9fa5}]/u'; preg_match($pattern, $str, $match); var_dump($match);

ANSI(GB2312)


&lt;?php $str = '中文'; $pattern = '/['.chr(0xb0).'-'.chr(0xf7).']['.chr(0xa1).'-'.chr(0xfe).']/'; preg_match($pattern, $str, $match); var_dump($match);

2. 正则表达式匹配页面中所有img标签中的src的值。


&lt;?php $str = '&lt;img alt="高清大图" id="color" src="color.jpg" /&gt;'; $pattern = '/&lt;img.*?src="(.*?)".*?\/?&gt;/i'; preg_match($pattern, $str, $match); var_dump($match);

来源:https://segmentfault.com/a/1190000017813507

搞定PHP面试 - 正则表达式知识点整理的更多相关文章

  1. 搞定PHP面试 - 变量知识点整理

    一.变量的定义 1. 变量的命名规则 变量名可以包含字母.数字.下划线,不能以数字开头. $Var_1 = 'foo'; // 合法 $var1 = 'foo'; // 合法 $_var1 = 'fo ...

  2. 搞定PHP面试 - 运算符知识点整理

    一.算术运算符 1. 概览 例子 名称 结果 $a + $b 加法 $a 和 $b 的和. $a - $b 减法 $a 和 $b 的差. $a * $b 乘法 $a 和 $b 的积. $a / $b ...

  3. 搞定PHP面试 - 函数知识点整理

    一.函数的定义 1. 函数的命名规则 函数名可以包含字母.数字.下划线,不能以数字开头. function Func_1(){ } //合法 function func1(){ } //合法 func ...

  4. [算法总结] 13 道题搞定 BAT 面试——字符串

    1. KMP 算法 谈到字符串问题,不得不提的就是 KMP 算法,它是用来解决字符串查找的问题,可以在一个字符串(S)中查找一个子串(W)出现的位置.KMP 算法把字符匹配的时间复杂度缩小到 O(m+ ...

  5. 【Android 面试基础知识点整理】

    针对Android面试中常见的一些知识点整理,Max 仅仅是个搬运工.感谢本文中引用文章的各位作者,给大家分享了这么多优秀文章.对于当中的解析,是原作者个人见解,有错误和不准确的地方,也请大家积极指正 ...

  6. 【搞定Jvm面试】 Java 内存区域揭秘附常见面试题解析

    本文已经收录自笔者开源的 JavaGuide: https://github.com/Snailclimb ([Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识)如果觉得不错 ...

  7. 两年经验拿到蚂蚁金服,字节offer,附上金九银十BAT面试核心知识点整理

    前言 我自己是本科毕业后在老东家干了两年多,老东家算是一家"小公司"(毕竟这年头没有 BAT 或 TMD 的 title 都不好意思报出身),毕业这两年多我也没有在大厂待过,因此找 ...

  8. 【搞定Jvm面试】 JVM 垃圾回收揭秘附常见面试题解析

    JVM 垃圾回收 写在前面 本节常见面试题 问题答案在文中都有提到 如何判断对象是否死亡(两种方法). 简单的介绍一下强引用.软引用.弱引用.虚引用(虚引用与软引用和弱引用的区别.使用软引用能带来的好 ...

  9. PHP面试-复习知识点整理

    false的七种情况 整型0 浮点0.0 布尔false 空字符串'',"" 字符串'0' 空数组[] NULL 超全局数组 $GLOBALS,包含下面8个超全局数组的值 $_GE ...

随机推荐

  1. <转>KMP算法详解

    看了好久的KMP算法,都一直没有看明白,直到看到了这篇博客http://www.tuicool.com/articles/e2Qbyyf让我瞬间顿悟. 如果你看不懂 KMP 算法,那就看一看这篇文章 ...

  2. Django 1.5.4 专题二 urls 和 view 提高

    一.修改article/urls.py内容如下 二.修改django_test/urls.py如下 三.修改article/views.py如下 四.修改templates/article.html的 ...

  3. java基础---->java输入输出流

    今天我们总结一下java中关于输入流和输出流的知识,博客的代码选自Thinking in java一书.我突然很想忘了你,就像从未遇见你. java中的输入流 huhx.txt文件的内容如下: I l ...

  4. HTTP/2笔记之帧

    零.前言 客户端和服务器端一旦握手协商成功接建立连接,端点之间可以基于HTTP/2协议传递交换帧数据了. 一.帧通用格式 下图为HTTP/2帧通用格式:帧头+负载的比特位通用结构: +-------- ...

  5. xcode官网下载地址

    https://developer.apple.com/downloads/

  6. Css-常用css

    /*怪异盒子模型*/ .box { box-sizing: border-box; } /*水平居中的内联块级*/ .inBlock { display: inline-block; vertical ...

  7. CodeForces Roads not only in Berland(并查集)

    H - Roads not only in Berland Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d ...

  8. poj3349 Snowflake Snow Snowflakes【HASH】

    Snowflake Snow Snowflakes Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 49991   Accep ...

  9. MySQL逗号分割字段的列转行

    前言: 由于很多业务表因为历史原因或者性能原因,都使用了违反第一范式的设计模式.即同一个列中存储了多个属性值(具体结构见下表). 这种模式下,应用常常需要将这个列依据分隔符进行分割,并得到列转行的结果 ...

  10. Python之numpy基本指令

    https://blog.csdn.net/mmm305658979/article/details/78745637 # -*- coding: utf-8 -*- 多加练习才是真 import n ...