PHP中的正则表达式

一、什么时候需要正则表达式

  • 数据验证
  • 字符串查找
  • 字符串替换

二、什么是正则表达式

正则表达式(Regular Expression)是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符")。 用它可以匹配、替换、截取匹配的字符串,在处理复杂字符操作的时候,可以提高工作效率,也在一定程度节省你的代码量。

PHP中的正则函数

  • 由PCRE库提供的函数,以preg_为前缀命名。现在得编程语言和软件中一般都使用PCRE库

    $str = "PHP编程";
    if (preg_match("/([0-9a-zA-Z\x{4e00}-\x{9fa5}]+)/u",$str, $matches)) {
    var_dump($matches);
    echo "\n";
    }
  • 由POSIX扩展的函数,以ereg_为前缀命名。

    自PHP5.3后就不再推荐使用POSIX正则函数库,若程序中使用会报:Deprecated级别的错误

三、正则表达式组成

定界符原子元字符模式修饰符(也有叫修正符)组成

1、定界符

除了字母、数字、正斜线、\ 以外的字符都可以作为定界符号。一般用/#;

$subject="jack is my name,so I'am jack";
$pattern='/jack/';
$pattern='#jack#';
$pattern='/jac/';
echo preg_match($pattern, $subject,$matches);
echo '<pre>';
print_r($matches);

$regex = '/^http:\/\/([\w.]+)\/([\w]+)\/([\w]+)\.html$/i';
$str = 'http://www.youku.com/show_page/id_ABCDEFG.html';
$matches = array();

if(preg_match($regex, $str, $matches)){
    var_dump($matches);
}

echo '<hr/>';

$regex = '#^http://([\w.]+)/([\w]+)/([\w]+)\.html$#i';
$str = 'http://www.youku.com/show_page/id_ABCDEFG.html';
$matches = array();

if(preg_match($regex, $str, $matches)){
    var_dump($matches);
}

2、原子

原子是匹配模式中最基础的组成部分,每个模式至少包含一个原子

2.1、普通原子

1、可见原子 a-z、A-Z、0-9 ( - 连字符表示范围 )
$subject="jack001 is my name,so I'am jack007";
$pattern='/jack[0-9]+/';
$pattern='#jack[0-9]+#';
$pattern='/jac/';
echo preg_match($pattern, $subject,$matches);
echo '<pre>';
print_r($matches);
2、不可见原子 \n,\r,\t,\v,\f
字符 含义
\f 匹配一个换页符。
\n 匹配一个换行符。
\r 匹配一个回车符。
\v 匹配一个垂直制表符
\t 匹配一个水平制表符
$subject="jack001 
        is my name,
        so I'am 
        jack007";
$pattern='/\n/';
echo preg_match_all($pattern, $subject,$matches);
echo '<pre>';
print_r($matches);

//\s
jack001
        is my name,so I'am jack007 //放到文件里查找

2.2、通用字符

标示 说明
\d 匹配任意一个十进制数字,等价于[0-9]
\D 匹配任意一个除了十进制数字以外的字符,等价于[^0-9]
\s 匹配任意一个空白字符,等价于[\f\n\r\t\v]
\S 匹配除空白以外任何一个字符,等价于[^\f\n\r\t\v]
\w 匹配任意一个数字、字母或下划线,等价于[0-9a-zA-Z_]
\W 匹配除数字、字母或下划线以外的任意一个字符,等价于[^0-9a-zA-Z_]
$subject="jack001 is my name,so I'am jack007";
$pattern='/\d/';
$pattern='/\D/';
$pattern='/\w/';
$pattern='/\W/';
echo preg_match_all($pattern, $subject,$matches);
echo '<pre>';
print_r($matches);

//实例二
$pattern = '/^[0-9a-zA-Z_]+@[0-9a-zA-Z_]+(\.[0-9a-zA-Z_]+){0,3}$/';
//vs
$pattern = '/^\w+@\w+(\.\w+){0,3}$/';

//实例三
$keywords = preg_split("/[\s,]+/", "hypertext language, programming");
print_r($keywords);

2.3、特殊字符

*`$ ( ) { [ \ . ] } ^ + ?`** 转义后使用

$subject="this is {\$var}";
$pattern='/[\{\}\$]/';
echo preg_match_all($pattern, $subject,$matches);
echo '<pre>';
print_r($matches);

2.4、自定义的

[abc] 表示: 匹配a 或者b 或者c

$pattern = '/[abcdef]/';
$subject = 'mystring';
$subject = 'hello boy';
echo preg_match_all($pattern, $subject,$matches);

3、元字符

编写一个正则表达式,我们要用到一些特殊的字符,而这些特殊的字符我们称之为元字符

3.1、限定

常用的限定符

符号 说明
* 匹配0次、一次或多次其前面的原子
+ 匹配1次或多次其前面的原子
? 匹配0次或1次其前面的原子
. 匹配处理换行符外的任意一个字符
| 匹配两个或多个分支选择
{n} 匹配其前面的原子恰好出现n次
{n,} 表示其前面的原子出现不少于n次
{n,m} 表示其前面的原子至少出现n次,最多出现m次
#a\s*b#   \s表示空白原子,可以匹配在a和b之间没有空白,一个或多个空白情况 

#a\d+b#   可以匹配在a和b之间有一个或多个数字的情况,如a2b,a34567b等

#a\W?b#   可以匹配在a和b之间有一个胡没有特殊字符。如ab,a#b,a%b等

#ax{4}b#  可以匹配在a和b之间必须有4个x的字符串,如axxxb

#ax{2,}b#  可以匹配在a和b之间要至少有2个x的字符,如axxb,axxxxxb等

#ax{2,4}b#  可以匹配在a和b之间至少有2个和最多有4个x的字符串,如果axxb,axxxb,和axxxb
  • 点(.)不匹配的换行符在win系统下是[^\n\r],UNIX系统中[^\n]
  • (.*?)贪婪模式和修饰符U一样的效果

3.2、定位

符号 说明
^或\A 匹配输入字符串的开始位置(或在多行模式下行的开头,即紧随一换 行符之后)
$或\Z 匹配输入字符串的结束位置(或在多行模式下行的结尾,即紧随一换行符之前)
\b 匹配单词的边界
\B 匹配除单词边界以外的部分
^jack       以"jack"开头的字符串
jack$       以"jack"结尾的字符串
^jack$      "jack"开头和结尾,(只能是聂哥自己 )

$subject='he and hello word and here';
$pattern='/he/';//想匹配单词he
$pattern='/\bhe\b/';//想匹配单词he

// $subject='this hello';
// $pattern='#\Bis#';//左边一定无边界
// $subject='singising  ';
// $pattern='#is\B#';//不以is结尾  右边一定无边界
// $pattern='#\Bis\B#';//不以is开始也不以is结尾

在字符串"This island is a beautiful land"中
元字符`\b`对单词的边界进行匹配;
/\bis\b/  匹配单词"is",不匹配"This"和"island"。
/\bis      匹配单词"is"和"island"中的"is",不匹配"This"
元字符“\B”对除单词边界以外的部分进行匹配。
/\Bis\B/  将明确的指示不与单词的左、右边界匹配,只匹配单词的内部。所以在这个例子中没有结果。
/\Bis      匹配单词"This"中的"is"

echo preg_match_all($pattern, $subject,$matches);
echo '<pre>';
print_r($matches);

3.3、范围指定

符号 说明
[ ] 匹配方括号中指定的任意一个原子
[^] 匹配除方括号中的原子以外的任意一个字符
( ) 匹配其整体为一个原子,即模式单元。可以理解为由多个单个原子组成的大原子
[a-z]                    a到z之间任意字母
[^A-Z]                   除了 A-Z这些之外的字符
(gif|jpeg)             "gif"或者 "jpeg"
[a-z]+                  一个或者多个 a到z之间任意字母
[0-9.-]                 0-9之间任意数字,或者 点 或者 横线
[a-zA-Z0-9_]{1,}$       至少一个字母数字下划线
([wx])([yz])            wy或wz或xy或xz
[^A-Za-z0-9]            字符数字之外的字符
([A-Z]{3}|[0-9]{4})    三个大写字母或者4个数字

小括号的作用有两个,一个是改变限定符的作用范围,例如(thirt|four)th表示匹配thirth,fourth,另外一个作用是分组,也就是子表达式,例如(.[0-9]{1,3}){3}是对分组进行操作

3.4 转义

如果想查找或匹配元字符本身,比如*?等就出现问题:没办法指定,因为它们会被解释成别的意思。这时就使用 \ 来取消这些字符的特殊意义

4、模式修饰符

用于开启或者关闭某种功能或模式

/正则表达式/模式修饰符

使用几个模式修饰符,它能使你的工作更容易,比如字母大小写敏感性、搜索多个行等等。

修饰符 说明
i 在正则匹配时不区分大小写
m 将字符串视为多行,当设定了此修正符,行起始(^)和行结束(\$)除了匹配整个字符串开头和结束外,还分别匹配其中的换行符(\n)的之后和之前
s 如果设定了此修正符,则模式中的圆点元字符.匹配所有的字符,包括换行符。即将字符串视为单行,换行符作为普通字符看待
x 忽略空白,除非进行转义的不被忽略。
U 匹配到最近的字符串, 禁止贪婪匹配,只跟踪到最近的一个匹配符并结束
D 如果设定了此修正符,模式中的行结束($)仅匹配目标字符串的结尾。没有此选项时,如果最后一个字符是换行符的话,也会被匹配在里面,如果设定了 m 修正符则忽略此选项
//i修饰
$subject = "jack is my name,so I'am JACK";
$pattern = '/jack/i';

$pattern = '/HELLO/';
$subject = 'hello word';

//m修饰
$subject = "jack is my name,\njack is my English name";
$pattern = '/^jack/i';//加上脱字符后只能匹配一个
$pattern = '/^jack/im';//加上修饰符m就匹配第二个jack

//s修饰
//注意此处的单双引号
$subject = "jack001 is my name,\njack is my English name"; 
$pattern = '/./';
$pattern = '/./s';

//x修饰
$subject = "jack is my name,\njack is my English name"; //注意此处的单双引号
$pattern = '/eng lish/';
$pattern = '/eng lish/ix';//x忽略模式中的空白字符

//U取消贪婪模式
$subject = '<strong>聂哥</strong><strong>帅</strong><strong>不</strong><strong>帅</strong>';
$pattern = '/<strong>.*<\/strong>/';
$pattern = '/<strong>.*<\/strong>/U';

//D修饰
$subject = "so I'm jack\n";
$pattern = '/jack$/';
$pattern = '/jack$/D';//加上D不匹配jack\n

echo preg_match_all($pattern, $subject,$matches);
echo '<pre>';
print_r($matches);

四、正则表达式运算符优先级

正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似

顺序 元字符 描述
1 \ 转义符
2 ()、(?:)、(?=)、 [] 括号和中括号
3 *,+,?,{n},{n,},{n,m} 限定符
4 ^,$,\b,\B,\A,\Z 边界限制
5 | 替换

字符具有高于替换运算符的优先级,使得"m|food"匹配"m"或"food"。若要匹配"mood"或"food",请使用括号创建子表达式,从而产生"(m|f)ood"

$pattern = '/ABC|BCD/';
//我们想是中间的C或者B,但是它只管ABC
$subject = 'ABCCD';
echo preg_match_all($pattern, $subject,$matchs);
echo '<pre>';
print_r($matchs);

断言

http://m.php.cn/article/390651.html demo

正则表达式校验密码
1、密码必须由数字、字符、特殊字符三种中的两种组成;
2、密码长度不能少于8个字符;
满足以上两点,应该怎么实现?

(?!^\\d+$)不能全是数字
(?!^[a-zA-Z]+$)不能全是字母
(?!^[_#@]+$)不能全是符号(这里只列出了部分符号,可自己增加,有的符号可能需要转义)
.{8,}长度不能少于8位
合起来就是
(?!^\\d+$)(?!^[a-zA-Z]+$)(?!^[_#@]+$).{8,}