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

版权声明:著作权归作者所有,转载请注明出处 https://blog.csdn.net/weixin_42565457/article/details/84891986

一、简介

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

二、语法

当使用 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];   // 结果为:string(15) "blog.snsgou.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)只允许英文字母、数字、下划线、英文句号、以及中划线组成

//[email protected] 
^[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

猜你喜欢

转载自blog.csdn.net/weixin_42565457/article/details/84891986