正则表达式的基本语法

#正则表达式的基本语法
正则一般用于验证表单,用户名,邮箱的准确性等等,简洁而强大.


#定界符
表示正则开始和结束,正则匹配模式使用分隔符与元字符组成,分隔符可以是非数字、非反斜线、非空格的任意字符。经常使用的分隔符是正斜线(/)、hash符号(#) 以及取反符号(~),
例如:

/foo bar/

\#^[^0-9]$#
 ~php~

#如果模式中包含分隔符,则分隔符需要使用反斜杠(\)进行转义。
例如:需要匹配http://
/http:\/\//


#如果模式中包含较多的分割字符,建议更换其他的字符作为分隔符,也可以采用preg_quote进行转义。

$p = 'http://';
$p = '/'.preg_quote($p, '/').'/';
echo $p;

#分隔符后面可以使用模式修饰符,模式修饰符包括:i, m, s, x等,例如使用i修饰符可以忽略大小写匹配:

$str = "Http://www.dxxing.com/";
if (preg_match('/http/i', $str)) {
     echo '匹配成功';
 }

#修饰符

>在PHP正则表达式里面的修饰符可以改变正则的很多特性,使得正则表达式更加适合你的需要(注意:修饰符对于大小写是敏感的,这意味着"e"并不等于"E")。

PHP正则表达式修饰符的种类及介绍:

 i :如果在修饰符中加上"i",则正则将会取消大小写敏感性,即"a"和"A" 是一样的。

 m:默认的正则开始"^"和结束"$"只是对于正则字符串如果在修饰符中加上"m",那么开始和结束将会指字符串的每一行:每一行的开头就是"^",结尾就是"$"。

 s:如果在修饰符中加入"s",那么默认的"."代表除了换行符以外的任何字符将会变成任意字符,也就是包括换行符!

 x:如果加上该修饰符,表达式中的空白字符将会被忽略,除非它已经被转义。

 e:本修饰符仅仅对于replacement有用,代表在replacement中作为PHP代码。

 A:如果使用这个修饰符,那么表达式必须是匹配的字符串中的开头部分。比如说"/a/A"匹配"abcd"。

 E:与"m"相反,如果使用这个修饰符,那么"$"将匹配绝对字符串的结尾,而不是换行符前面,默认就打开了这个模式。

 U:和问号的作用差不多,用于设置"贪婪模式"。

#元字符与转义
>正则表达式中具有特殊含义的字符称之为元字符,常用的元字符有:

 \ 一般用于转义字符
 ^ 断言目标的开始位置(或在多行模式下是行首)
 $ 断言目标的结束位置(或在多行模式下是行尾)
 . 匹配除换行符外的任何字符(默认)
 [ 开始字符类定义
 ] 结束字符类定义
 | 开始一个可选分支
 ( 子组的开始标记

 ) 子组的结束标记
 ? 作为量词,表示 0 次或 1 次匹配。位于量词后面用于改变量词的贪婪特性。 (查阅量词)
 * 量词,0 次或多次匹配
 + 量词,1 次或多次匹配
 { 自定义量词开始标记
 } 自定义量词结束标记

下面的\s匹配任意的空白符,包括空格,制表符,换行符。[^\s]代表非空白符。[^\s]+表示一次或多次匹配非空白符。
$p = '/^我[^\s]+(苹果|香蕉)$/';

    $str = "我喜欢吃苹果";
    if (preg_match($p, $str)) {
        echo '匹配成功';
    }
元字符具有两种使用场景,一种是可以在任何地方都能使用,另一种是只能在方括号内使用,在方括号内使用的有:

 \ 转义字符
 ^ 仅在作为第一个字符(方括号内)时,表明字符类取反
 - 标记字符范围
 其中^在反括号外面,表示断言目标的开始位置,但在方括号内部则代表字符类取反,方括号内的减号-可以标记字符范围,例如0-9表示0到9之间的所有数字。
下面的\w匹配字母或数字或下划线。
    $p = '/[\w\.\-]+@[a-z0-9\-]+\.(com|cn)/';
    $str = "我的邮箱是Spark.eric@imooc.com";
    preg_match($p, $str, $match);
    echo $match[0];

##贪婪模式与懒惰模式
>正则表达式中每个元字符匹配一个字符,当使用+之后将会变的贪婪,它将匹配尽可能多的字符,但使用问号?字符时,它将尽可能少的匹配字符,既是懒惰模式。

 贪婪模式:在可匹配与可不匹配的时候,优先匹配
 下面的\d表示匹配数字

        $p = '/\d+\-\d+/';
        $str = "我的电话是010-12345678";
        preg_match($p, $str, $match);
        echo $match[0]; //结果为:010-12345678

 懒惰模式:在可匹配与可不匹配的时候,优先不匹配
    
        $p = '/\d?\-\d?/';
        $str = "我的电话是010-12345678";
        preg_match($p, $str, $match);
        echo $match[0];  //结果为:0-1

当我们确切的知道所匹配的字符长度的时候,可以使用{}指定匹配字符数

    $p = '/\d{3}\-\d{8}/';
    $str = "我的电话是010-12345678";
    preg_match($p, $str, $match);
    echo $match[0]; //结果为:010-12345678

#正则语法
 原子 可见原子unicode 不可见 换行符\n 回车\r 制表符\t 空格
 |:匹配两个或多个分支选择
 []:匹配方括号中的任意一个原子;
 [^]:匹配除方括号中的原子之外的任意字符

#元字符
 原子的集合
 . 匹配除换行符以外的任意字符,即[^\n]
 \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_]

#量词
 {n}  表示其前面的原子恰好出现n次;
 {n,} 表示其前面的原子最少出现n次; {n,m}表示其前面的原子最少出现n次,最多出现m次;
 *    匹配0次,1次或者多次其之前的原子,即{0,}
 +    匹配1次或者多次其之前的原子,即{1,}
 ?    匹配0次或者1次其之前的原子,即{0,1}

#边界控制与模式单元
 ^ 匹配字符串开始的位置
 $ 匹配字符串结尾的位置

 ()匹配其中的整体为一个原子

()匹配其中的整体为一个原子
会把空号里面的当做原子来看待,可以与()后面的字符组成模式单元


#修正模式
>给正则表达式指定一种匹配模式

 贪婪匹配 :匹配长的
 懒惰匹配:匹配短的
 在结束符 /后面加大U
 默认贪婪模式,匹配最长的
    
        $pattern
        preg_match($pattern,$String,matchs)

默认 贪婪匹配:匹配结果存在歧义时取其长,默认匹配模式,添加在匹配模式的最后面,实例/0-9/
 U 懒惰匹配,匹配结果存在歧义时取其短,实例/0-9/U
 i 忽略英文字母大小写,实例/aabb/i
 x 忽略空白,实例/aa bb/x
 s 让元字符"."匹配包括换行在内的所有字符
 .+ 匹配非空


#工具
在线正则工具 http://zhilan.net/app/regexpal/

#常见正则
浮点数匹配保留两位小数

    \d+\.\d{2}$
11位手机号

    ^1[34578]\d{9}$
匹配邮箱

    ^\w+(\.\w+)*@\w+(\.\w+)+$
匹配网址

    ^(https?://)?(\w+\.)+[a-zA-Z]+$

#使用正则表达式进行匹配
使用正则表达式的目的是为了实现比字符串处理函数更加灵活的处理方式,因此跟字符串处理函数一样,其主要用来判断子字符串是否存在、字符串替换、分割字符串、获取模式子串等。
PHP使用PCRE库函数来进行正则处理,通过设定好模式,然后调用相关的处理函数来取得匹配结果。
preg_match用来执行一个匹配,可以简单的用来判断模式是否匹配成功,或者取得一个匹配结果,他的返回值是匹配成功的次数0或者1,在匹配到1次以后就会停止搜索。
    
    $subject = "abcdef";
    $pattern = '/def/';
    preg_match($pattern, $subject, $matches);
    print_r($matches); //结果为:Array ( [0] => def )

上面的代码简单的执行了一个匹配,简单的判断def是否能匹配成功,但是正则表达式的强大的地方是进行模式匹配,因此更多的时候,会使用模式:

    $subject = "abcdef";
    $pattern = '/a(.*?)d/';
    preg_match($pattern, $subject, $matches);
    print_r($matches); //结果为:Array ( [0] => abcd [1] => bc )
通过正则表达式可以匹配一个模式,得到更多的有用的数据。


查找所有匹配结果
preg_match只能匹配一次结果,但很多时候我们需要匹配所有的结果,preg_match_all可以循环获取一个列表的匹配结果数组。

    $p = "|<[^>]+>(.*?)]+>|i";
    $str = "example:

this is a test

";
    preg_match_all($p, $str, $matches);
    print_r($matches);
可以使用preg_match_all匹配一个表格中的数据:

 

    $p = "/(.*?)<\/td>\s*(.*?)<\/td>\s*<\/tr>/i";
    $str = "

Eric 25
John 26

";
    preg_match_all($p, $str, $matches);
    print_r($matches);
$matches结果排序为$matches[0]保存完整模式的所有匹配, $matches[1] 保存第一个子组的所有匹配,以此类推。

正则表达式的搜索和替换
正则表达式的搜索与替换在某些方面具有重要用途,比如调整目标字符串的格式,改变目标字符串中匹配字符串的顺序等。
例如我们可以简单的调整字符串的日期格式:

    $string = 'April 15, 2014';
    $pattern = '/(\w+) (\d+), (\d+)/i';
    $replacement = '$3, ${1} $2';
    echo preg_replace($pattern, $replacement, $string); //结果为:2014, April 15
其中${1}与$1的写法是等效的,表示第一个匹配的字串,$2代表第二个匹配的。
通过复杂的模式,我们可以更加精确的替换目标字符串的内容。

    $patterns = array ('/(19|20)(\d{2})-(\d{1,2})-(\d{1,2})/',
                       '/^\s*{(\w+)}\s*=/');
    $replace = array ('\3/\4/\1\2', '$\1 =');//\3等效于$3,\4等效于$4,依次类推
    echo preg_replace($patterns, $replace, '{startDate} = 1999-5-27'); //结果为:$startDate = 5/27/1999

详细解释下结果:(19|20)表示取19或者20中任意一个数字,(\d{2})表示两个数字,(\d{1,2})表示1个或2个数字,(\d{1,2})表示1个或2个数字。^\s*{(\w+)\s*=}表示以任意空格开头的,并且包含在{}中的字符,并且以任意空格结尾的,最后有个=号的。
用正则替换来去掉多余的空格与字符:
$str = 'one     two';
$str = preg_replace('/\s+/', ' ', $str);
echo $str; // 结果改变为'one two'

#例子

                 $user = array(
            'name' => 'bs123',
            'email' => '83507315@qq.com',
            'mobile' => '15888888888'
        );
        //进行一般性验证
        if (empty($user)) {
            die('用户信息不能为空');
        }
        if (strlen($user['name']) < 6) {
            die('用户名长度最少为6位');
        }
        //用户名必须为字母、数字与下划线
        if (!preg_match('/^\w+$/i', $user['name'])) {
            die('用户名不合法');
        }
        //验证邮箱格式是否正确
        if (!preg_match('/^[\w\.]+@\w+\.\w+$/i', $user['email'])) {
            die('邮箱不合法');
        }
        //手机号必须为11位数字,且为1开头
        if (!preg_match('/^1\d{10}$/i', $user['mobile'])) {
            die('手机号不合法');
        }
        echo '用户信息验证成功';