PHP强化之11 - PCRE正则表达式

----- 最近更新【2021-12-15】-----

PHP强化系列--目录

一、简介

正则表达式是一种描述字符串结果的语法规则,是一个特定的格式化模式,可以匹配、替换、截取匹配的字符串。

二、语法

当使用 PCRE 函数的时候,模式需要由分隔符闭合包裹。分隔符可以使任意非字母数字、非反斜线、非空白字符。经常使用的分隔符是正斜线(/)、hash符号(#) 以及取反符号(~)。

合法模式示例:

/<\/\w+>/
#^[^0-9]$#
|(\d{3})-\d+|Sm       ## 可以在结束分隔符后面增加模式修饰符
/^(?i)php[34]/
{^\s+(\s+)?$}       ## 括号样式的分隔符,左括号和右括号分别作为 开始和结束 分隔符。
%[a-zA-Z0-9_-]%

非法模式示例:

/href='(.*)'     ## 缺失结束分隔符
/\w+\s*\w+/J     ## 未知模式修饰符"J"
1-\d3-\d3-\d4|     ## 缺失开始分隔符

如果分隔符需要在模式内进行匹配,它必须使用反斜线进行转义。如果分隔符经常在 模式内出现, 一个更好的选择就是是用其他分隔符来提高可读性。

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

三、正则表达式

由上面介绍的合法分隔符所包含的部分,就是我们主要去了解的正则表达式部分了。下面我将对一些常用的部分做一下归类:

1、 原子
原子是组成正则表达式的基本单位,在分析正则表达式时,应作为一个整体。
包括以下内容:
> 单个字符、数字,如a-z,A-Z,0-9。
> 模式单元,如(ABC)可以理解为由多个原子组成的大的原子。
> 原子表,如 [ABC]。
> 重新使用的模式单元,如:\1
> 普通转义字符,如:\d, \D, \w
> 转义元字符,如:\*,\.
> 元字符

2、元字符

  • ^ 断言目标的开始位置(或在多行模式下是行首)
  • $ 断言目标的结束位置(或在多行模式下是行尾)
  • . 表示任意一个除换行符之外的字符
  • [] 表示单个字符的原子表
    [^] 表示除中括号内原子之外的任何字符 是[]的取反
    [-] 表示允许的范围,如[0-9]表示任意一位数字
  • {m} 表示对前面原子的数量控制,表示是m次
    {m,} 表示对前面原子的数量控制,表示是至少m次
    {m,n}表示对前面原子的数量控制,表示是m到n次
  • * 量词,0 次或多次匹配,等价于{0,}
  • + 量词,1 次或多次匹配,等价于{1,}
  • ? 作为量词,表示 0 次或 1 次匹配,等价于{0,1} 。位于量词后面用于改变量词的贪婪特性。
  • () 表示一个整体原子,【还有一个子存储单元的作用】。 也可以使用?:来拒绝子存储。 (?:.*?)
  • | 开始一个可选分支

3、常用转义字符

说明
\d 匹配一个数字;等价于[0-9]
\D 匹配除数字以外任何一个字符;等价于[^0-9]
\w 匹配一个英文字母、数字或下划线;等价于[0-9a-zA-Z_]
\W 匹配除英文字母、数字和下划线以外任何一个字符;等价于[^0-9a-zA-Z_]
\s 匹配一个空白字符;等价于[\f\n\r\t\v]
\S 匹配除空白字符以外任何一个字符;等价于[^\f\n\r\t\v]
\n 匹配一个换行符
\r 匹配一个回车符

4、模式修整符

  • i 表示不区分大小写;
    如:"/[a-zA-Z]/" 等价于 "/[a-z]/i"
  • s 表示匹配视为单行
    如果设置了这个修饰符,模式中的点号元字符匹配所有字符,包含换行符。如果没有这个 修饰符,点号不匹配换行符。
  • U 表示拒绝贪婪匹配
    通过量词后紧跟? 的方式可以使其成为贪婪的,注意这和 模式修整符U 是不能同时使用的,只能取其一。
  • x 忽略空白字符

5、惰性匹配

函数符 描述
*? 零次或多次,但尽可能少的匹配
+? 一次或多次,但尽可能少的匹配
?? 0次或1次,但尽可能少的匹配
{n,}? 至少n次,但尽可能少的匹配
{n,m}? n到m次 ,但尽可能少的匹配

四、相关函数

1、preg_match
int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
搜索subject与pattern给定的正则表达式的一个匹配。

如果提供了参数matches,它将被填充为搜索结果。 $matches[0]将包含完整模式匹配到的文本, $matches[1] 将包含第一个捕获子组匹配到的文本,以此类推。

函数返回值为0或1。

如:

$label = 'content/112abc';
$a = preg_match('#content/(\d+)(\w*)#i', $label, $mc);
var_dump($a);
var_dump($mc);

结果:

int(1)
array(3) {
  [0] =>
  string(14) "content/112abc"
  [1] =>
  string(3) "112"
  [2] =>
  string(3) "abc"
}

注意:
preg_match() 第一次匹配成功后就会停止匹配,如果要实现全部结果的匹配,即搜索到subject结尾处,则需使用preg_match_all() 函数。

2、preg_match_all
int preg_match_all ( string $pattern , string $subject [, array &$matches [, int $flags = PREG_PATTERN_ORDER [, int $offset = 0 ]]] )
搜索subject中所有匹配pattern给定正则表达式 的匹配结果并且将它们以flag指定顺序输出到matches中。在第一个匹配找到后, 子序列继续从最后一次匹配位置搜索。

该函数返回完整匹配次数(可能是0),或者如果发生错误返回FALSE。

参数说明:

参数 说明
pattern 正则表达式
subject 需要匹配检索的对象
matches 存储匹配结果的数组
flags 可选,指定匹配结果放入 matches 中的顺序,可供选择的标记有:
1)PREG_PATTERN_ORDER:默认,对结果排序使 $matches[0] 为全部模式匹配的数组,$matches[1] 为第一个括号中的子模式所匹配的字符串组成的数组,以此类推
2)PREG_SET_ORDER:对结果排序使 $matches[0] 为第一组匹配项的数组,$matches[1] 为第二组匹配项的数组,以此类推
3)PREG_OFFSET_CAPTURE:如果设定本标记,对每个出现的匹配结果也同时返回其附属的字符串偏移量

如:

$userinfo = "Name: <b>PHP</b> <br> Title: <b>Programming Language</b>";
preg_match_all ("/<b>(.*)<\/b>/U", $userinfo, $pat_array);
print_r($pat_array[0]);

结果:

Array
(
    [0] => <b>PHP</b>
    [1] => <b>Programming Language</b>
)

3、preg_replace
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
搜索subject中匹配pattern的部分, 以replacement进行替换。

$string = 'April 15, 2003';
$pattern = '/(\w+) (\d+), (\d+)/i';
$replacement = '${1}1,$3';
echo preg_replace($pattern, $replacement, $string);
//输出:April1,2003

4、preg_split
通过一个正则表达式分隔给定字符串.
array preg_split ( string $pattern , string $subject [, int $limit = -1 [, int $flags = 0 ]] )

如:

//使用逗号或空格(包含" ", \r, \t, \n, \f)分隔短语
$keywords = preg_split("/[\s,]+/", "hypertext language, programming");
print_r($keywords);

结果:

Array
(
    [0] => hypertext
    [1] => language
    [2] => programming
)

5、其它
1)preg_grep
array preg_grep ( string $pattern , array $input [, int $flags = 0 ] )
返回给定数组input中与模式pattern 匹配的元素组成的数组

2)preg_quote
string preg_quote ( string $str [, string $delimiter = NULL ] )
转义正则表达式字符

五、经典实例

1、关于URL
1)从url中取得主机名

$url = "http://blog.nosee123.com/index.php";
preg_match("/^(http:\/\/)?([^\/]+)/i",$url, $matches);
$host = $matches[2]; 
echo $host;  // 结果为:string(15) "blog.nosee123.com"

2)判断字符串是否为url

/^http(s?):\/\/([\w]+\.?)++\/*[\w\.]*\??[\w=&\+\%]*/is

2、关于Email
1)判断字符串是否是邮箱

/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/
^[a-zA-Z0-9][a-zA-Z0-9._-]*@[a-zA-Z0-9]+\.[a-zA-Z0-9\.]+$

2)只允许英文字母、数字、下划线、英文句号、以及中划线组成

//gaozihang-001@gmail.com 
^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$

3、关于字符
1)任意一位大小字母或数字下划线:

[A-Za-z0-9_]   等价于  \w

4、数字相关
1)手机号码

 [1][3-8][0-9]{9}    //粗略匹配
^((13[0-9])|147|(15[0-35-9])|180|182|(18[5-9]))[0-9]{8}$

Or:

# 中国大陆手机号 (移动/联通/电信):
/^1(3[0-9]|4[5-9]|5[0-35-9]|66|7[013-8]|8[0-9]|9[89])\d{8}$/
# 中国移动:
/^1(34[0-8]|3[5-9\d]|440|4[78]\d|5[0-27-9]\d|70[356]|78\d|8[2-478]\d|98\d)\d{7}$/
# 中国联通:
/^1(3[0-2]\d|4[56]\d|5[56]\d|66\d|70[4789]|71|7[56]\d|8[56]\d)\d{7}$/
# 中国电信:
/^1(3[3]\d|349|410|49\d|53\d|70[0-2]|7[37]\d|740|8[019]\d|99\d)\d{7}$/

2)ip地址

\d+\.\d+\.\d+\.\d+

3)身份证

^(([0-9]{15})|([0-9]{18})|([0-9]{17}x))$

5、中文匹配

中文匹配:UTF-8汉字编码范围是0x4e00-0x9fa5;在ANSI(gb2312)环境下,0xb0-0xf7,0xa1-0xfe。
UTF-8要使用u模式修正符使模式字符串被当成UTF-8,在ANSI(gb2312环境下),使用chr将Ascii码转换为字符。

[\x{4e00}-\x{9fa5}]    #utf-8中文
[\u4e00-\u9fa5]    #通用

5、HTML页面的匹配

1)取出页面中所有img标签的src值

'/<img.*?src=("|\')(.*?)("|\').*?\/?>/i'

2)判断是否为a链接

/<a .*?href="(.*?)".*?>/is

参考:

官方手册:http://php.net/manual/zh/pcre.pattern.php

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • 概述 正则表达式是一种描述字符串结果的语法规则,是一个特定的格式化模式,可以匹配、替换、截取匹配的字符串。常用的语...
    醉于麦田阅读 492评论 0 0
  • 正则表达式介绍 正则表达式简介 正则表达式是用于描述字符排列和匹配模式的一种语法规则。它主要用于字符串的模式分割、...
    dptms阅读 10,907评论 1 9
  • 关于PCRE的介绍以及实现正则表达式功能的所有说明,都可以在官方手册中看到:正则表达式(兼容 Perl) 一、认识...
    拿破仑蛋糕阅读 1,605评论 0 1
  • PHP常用正则表达式汇总 正则表达式在 PHP 中的应用在 PHP 应用中,正则表达式主要用于: 正则匹配:根据正...
    DragonRat阅读 1,457评论 0 4
  • 原创 2017年12月28日 文/茹云 正如我所遇到的问题一样,开始对哲学或者工具类的书籍总是半截不通。其实,...
    茹云阅读 284评论 0 2