正则表达式之难点

  • 断言 ?<= 这个是对需要匹配的目标左边的(前面)的进行断言,断定它前面会出现的 但是不会被匹配到。如:
$subject = 'I am Lancer, Please say hello Lancer';

//目标: 我要把hello 后面的Lancer  改为  '!' .
$pattern = '/(?<=hello )Lancer/';
$result = preg_replace($pattern, '', $subject);
echo $result;  //I am Lancer, Please say hello !
这样就成功咯~
  1. ?=,与上面的位置刚好相反,这个是对需要匹配的目标右边的(后面)的进行断言,断定它后面会出现的 但是不会被匹配到。如:
$subject = 'I love you! I love her too!';

//目标:不能爱这么多, 把第二个 'love' 改为 'hate'
$pattern = '/love(?= her)/';
$result = preg_replace($pattern, 'hate', $subject);
echo $result;  //'I love you! I hate her too!'
  1. ?<!这个是需要对匹配左边的(前面的)进行断言,不过它是非,找到不是这个的。还是拿第一个例子来说:
$subject = 'I am Lancer, Please say hello Lancer';

//目标: 我还是要把hello 后面的Lancer  改为  '!'  该怎么做
$pattern = '/(?<!am )Lancer/';  //找到‘Lancer’前面不是'am '的'Lancer'
$result = preg_replace($pattern, '', $subject);
echo $result;  //I am Lancer, Please say hello !
  1. ?!还是一样的秘方,还是一样的味道~
$subject = 'I love you! I love her too!';

//目标:不能爱这么多, 把第二个 'love' 改为 'hate'
$pattern = '/love(?! you)/';
$result = preg_replace($pattern, 'hate', $subject);
echo $result;  //'I love you! I hate her too!'

总结:这个断言,作用主要在,对于很多同样的目标,可是我只要其中的一个,或者多个的时候,那么就可以根据它的前面和后面,进行断言,来区分他们找到自己想要匹配的目标。

  • 捕获 先来说一下, 什么叫捕获。就是匹配之后,会根据你正则表达式中的()来进行分组。一一捕获。打个比方:
//为了显示方便,写了个show函数
function show($str)
{
    if (empty($str)) {
        echo null;
    } elseif (is_array($str) || is_object($str)) {
        echo '<pre>';
        print_r($str);
        echo '</pre>';
    } else {
        echo $str;
    }
}
//--------------------------------------------------------------------
$subject  = '12323abcdea1233';
$pattern = '/(a)(b)(c)(d)(e)/';
preg_match_all($pattern, $subject, $matches);
show($matches);
//那么你会觉得 $matches 会是什么答案?
//你肯定知道是:
Array
(
    [0] => Array
        (
            [0] => abcde
        )

    [1] => Array
        (
            [0] => a
        )

    [2] => Array
        (
            [0] => b
        )

    [3] => Array
        (
            [0] => c
        )

    [4] => Array
        (
            [0] => d
        )

    [5] => Array
        (
            [0] => e
        )

)
//这个答案,大家应该都知道吧。索引为0的是整个match的内容,接着的
//就是捕获的每一个()分组的内容。我们还可以这样来写:

$subject = '123abcabc123';
$pattern = '/(a)(b)(c)(\1)(\2)(\3)/';
preg_match_all($pattern, $subject, $matches);
show($matches);//??
先看答案:
Array
(
    [0] => Array
        (
            [0] => abcabc
        )

    [1] => Array
        (
            [0] => a
        )

    [2] => Array
        (
            [0] => b
        )

    [3] => Array
        (
            [0] => c
        )

    [4] => Array
        (
            [0] => a
        )

    [5] => Array
        (
            [0] => b
        )

    [6] => Array
        (
            [0] => c
        )

)
//你可能会有疑问, 咦,,, 怎么(\1)和(a), (\2)和(b),(\3)和(c) 在正则里是一样的呢?
//其实 (a)就是指的第一组, 然后后面就可以用(\1)来表示。(b),(c)也一样。

有人可能就会问了, 那你写这个的作用又是什么呢 ? 获取这些括号里的干啥。。 我只要第一个索引的匹配就够了呀。

但是, 你考虑到了替换这个因素没? 如果我替换的时候需要()的东西呢? 这个时候,我们就可以用到捕获到的()的东西来穿插。

不知道有人好奇过没,为什么用那些TP框架,Laravel框架, 或者smarty 在模版里写的{{$msg}}为什么也能输出呢? 其实就是用了正则替换~ 看代码:

$msg = "正则捕获";
$subject = '<p>{{$msg}}</p>';
$pattern = '/\{\{(.*/)\}\}/';  //因为正则里也有'{' 和'}'所以需要用‘\’转义
$result = preg_replace($pattern, '<?php echo $1; ?>', $subject);
show($result); // <p><?php echo $msg;?></p> 
//成功修改~

上面说的是捕获, 但是我可能不想捕获怎么办? 那么就可以用(?:) 在前面加上?:即可。注意, 这个不会影响匹配 只会影响捕获。 如:

$subject = 'abc';
$pattern = '/(a)(?:b)(c)/';
preg_match_all($pattern, $subject, $matches);
show($matches);
//结果:
Array
(
    [0] => Array
        (
            [0] => abc
        )

    [1] => Array
        (
            [0] => a
        )

    [2] => Array
        (
            [0] => c
        )
)
//看 匹配的结果让然是'abc' 不过没有捕获到 'b'

以上就是基本的难点了, 纯手打和个人想法写完~ 谢谢观看,欢迎吐槽!