正则速查

正则表达式

  • 元字符

    • . [匹配除换行符以外的任意字符]
    • \w [匹配字母数字下划线或汉字]
    • \s [匹配任意空白符]
    • \b [匹配单词的开始或结束]
    • * [匹配0-n次连续出现的字符]
    • + [匹配1-n次连续出现的字符]
    • ? [匹配0-1次出现的字符]
    • ^ [匹配相反的字符]

    example:非(提取a标签内容)
            $reg='#<a[^>]*>([^<>]*)<\/a>#';
            $str="<a href='ssss'>some</a>other<a href='ddd'>some</a>";
            $res=preg_match_all($reg,$str,$m);
    
  • 字符组
    • [] [匹配单个字符,故? * . {}等不需在其中转义]
  • 分支
    • | [匹配可能存在的多种情况(可以多字符)]*需注意顺序*
  • 分组

    • (exp) [匹配exp,并捕获文本到自动命名的组里]
    • (?<name>exp) [匹配exp,捕获到名称为name的组里 | 反向引用中\k<name>]
    • (?:exp) [匹配exp,但不捕获也不分配组号]

      组号分配中,从左到右,先分配无组名的,在分配有组名的


    • (?=exp) [匹配exp前面的位置]
    • (?<=exp) [匹配exp后面的位置]
    • (?!exp) [匹配后面不是exp的位置]
    • (?<!exp) [匹配前面不是exp的位置]

      断言匹配的是一个事实,不是内容


    example:数字加千分位 同number_format
            $reg="#\\d{1,3}(?=(\\d{3})+(?:[.|$]))#";
            $str="1234567891238.5646656567";
            $res=preg_replace_callback($reg,
                    function($matches){
                    return ($matches[0].',');
                    },$str);
    example:否定环视,提取非p标签内的内容
            $reg='#<(?!p)([^>\s]+)\s*(?:[^>]+)?>(.*?)</\1>#';
            $str="<p>sdfd</p><div>dddiv</div>dom<img src='aaa'/><a href='ssss'>some</a>other";
            $res=preg_match_all($reg,$str,$m);
    

    • (?#comment) [提供注释以供阅读]
  • 反向引用

    • \1,\2 ... [用于重复前边匹配到的对应分组内容]
    • \k<name>或(?P=name) [有组名的反向引用]

    example:为了匹配到内容不是 "this is a '
            $reg="#(\"|').*?\\1#";
            //$reg="#(?P<quote>\"|').*?(?P=quote)#";
            $str="\"this is a 'string'\"";
            preg_match($reg,$str,$m);
    
  • 懒惰匹配

    • *? 重复任意次,但尽可能少

    example:若无 ?,会一直匹配到结尾的[/url]
            $reg="#\\[url\\](.*?)\\[\\/url\\]#";
            $str="[url]1.png[/url][url]2.png[/url][url]3.png[/url]";
            $res=preg_replace($reg,"<img src='$1'/>",$str);
    
  • 模式

    • 忽略大小写
      • #...#i [全局]
      • (?i)c [局部,对其后字符影响]
  • 多行模式

    • #...#m [每一行都单独去匹配,另外,$默认表示最后一行]

-点号通配模式

- `#...#s        [使其中的.可以通配换行符,达到跨行效果,多用于大段文字匹配]`
  • 懒惰模式

    • #...#U [同懒惰字符?]
  • 结尾限制

    • #...#D [有$存在是结尾不可有\n]
  • 支持UTF-8转义表达

    • #...#u [对模式中字符串当做utf8]

    example:utf8中文检测
            $str="php百度";
            $reg='#^[\x{4e00}-\x{9fa5}]+$#u';
            if(preg_match($reg,$str,$m)){
                echo '全部为中文';
            }else{
                echo '不全是中文';
            }
    

优化正则

  • 使用字符组代替分支条件
    • [a-c]比(a|b|c)效率高
  • 相同开头分支条件,优先放有不同处的分支在前边
    • 如邮编匹配,三位或四位区号
  • 标准量词是匹配优先的
    • \w*(\d+)去匹配copy2003y,匹配结果会是3,因为\w*贪婪匹配到整个字符串,然后\d+匹配不到,会书到3才结束,要改为懒惰模式\w*?
  • 能确定范围就不要用 “.”,能确定重复次数就不要用 ““ 或 *”+”,能用懒惰就不用贪婪模式
  • 合理使用(),对于不需要捕获的尽量使用(?:…)
  • 起始、行描点优化,加上^,$,并尽量与分组分离
  • 对大而全的正则拆分
  • 优先使用php内置函数代替正则
    • 输入的校验用filter更合理filter_var(‘admin@qq.com’,FILTER_VALIDATE_EMAIL)
    • 分析源代码tokenizer
如有疑问,请留言或邮件newbvirgil@gmail.com
本文链接 : http://blog.newbmiao.com/2015/02/28/regex-notes.html