----- 最近更新【2021-12-15】-----
一、简介
正则表达式是一种描述字符串结果的语法规则,是一个特定的格式化模式,可以匹配、替换、截取匹配的字符串。
二、语法
当使用 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