鬼斧神工的正则表达式(PHP语言)

文章目录
  1. 1. 写在前面
  2. 2. 与正则表达式的初次邂逅
  3. 3. 学习准备
    1. 3.1. 正则表达式的函数解析
      1. 3.1.1. 函数参数说明
  4. 4. 正则表达式基本语法
    1. 4.1. 界定符
    2. 4.2. regexpal工具
    3. 4.3. 原子:
    4. 4.4. 元字符:
    5. 4.5. 量词:
    6. 4.6. 边界控制与模式单元:
  5. 5. 修正模式
  6. 6. 常见正则表达式练习
  7. 7. 实战:正则工具类的设计实现

鬼斧神工之正则

写在前面

正则表达式对于程序员应该算是一个必备的技能了,所以我以PHP语言为载体进行了对正则表达式的学习,也借此继续学习PHP语言,如果需要可以本文中的PHP语言翻译成其他所需的语言。
同时推荐学习正则表达式之前先了解一些基本的语法,基本的OOP思想,基本的MVC模式知识。

与正则表达式的初次邂逅

对于正则表达式,可以在我们使用的很多产品中都有,比如在手机输入法/WINDOWS的文件搜索/WEB界面上对邮箱等的匹配从而判断邮箱是否正确,可以说正则表达式是无孔不入的,借用慕课网中badguy老师对正则表达式的评价:外表风骚,内功深厚!

学习准备

正则表达式的函数解析

PHP中内置的正则表达式的常用函数,函数参数只是列出了必要的参数,对于函数详细用法小伙伴们可以自行查询PHP手册或者自行Google或者百度~
同时建议下面列出的函数可以两两分组进行比较学习。

preg_match($pattern, $subject)
preg_match_all($pattern, $subject, $matches)

1.preg_match($pattern,$subject,$matches)只将第一个匹配到的结果赋值给$matches,$matches为一维数组。preg_match返回值为匹配到的次数,0或1.
2.preg_match_all($pattern,$subject,$matches)将所有匹配到的结果赋值给$matches,$matches为二维数组。
preg_match_all返回值为匹配到的次数。

preg_replace($pattern, $replacement, $subject)
preg_filter($pattern, $replacement, $subject)

preg_filter()和preg_replace()区别:在对数组方面替换的时候,preg_replace()会返回所有结果,preg_filter()只会返回替换到的结果。

preg_grep($pattern, array $input)

只匹配,不替换,返回匹配到的数组值

preg_split($pattern, $subject)

区别explode(…)

preg_quote($str)

比较简单,它会将正则表达式中的特殊字符进行转义。
regex的运算符: . \ + * ? [ ^ ] $ ( ) { } = ! < > | : -
转义符号 \

函数参数说明

为了大家阅读方便,也建议大家在使用过程中使用~

$pattern = 正则表达式
$subject = 匹配的目标数据

即为在文章或者示例代码中,$pattern 定义的为正则表达式,而 $subjiect 定义的为匹配的目标数据

正则表达式基本语法

正则表达式基本语法归类:

  • 界定符
  • 原子
  • 量词
  • 边界控制
  • 模式单元

虽然第一次学习感觉这些名词都很陌生,但是我相信小伙伴都可以学的明白,因为像我这么善良纯洁的新鲜小码农都了解了,你肯定没有问题啦~

界定符

界定符 :表示一个正则表达式的开始和结束;EG:/[0-9]/;
$pattern = ‘/[0-9]/‘ 或者 #[0-9]# {[0-9]}(不推荐使用大括号);

regexpal工具

正则表达式书写辅助工具 regexpal 是Google Code上的一个开源项目,可以实时匹配正则表达式,方便调试,使用HTML和JS开发,推荐给大家使用。
在线版截图

原子:

可见原子:Unicode编码表中用键盘输出后肉眼可见的字符

  • 标点 _ ;,?等等
  • 英文字母和数字
  • 汉字/日文等其他语言文字
  • 求和等数理化公式符号
  • 其他可见字符
    特殊原子:\ 因为本身还是转义字符,所以要用\才能匹配到一个\符号
    不可见原子:Unicode编码表中用键盘输出后肉眼不可见的字符
  • 换行符 \n
  • 回车符 \r
  • 制表符 \t
  • 空格
  • 其他不可见符号

原子和不可见原子都能用正则表达式进行原子匹配。

元字符:

[] -> 匹配出现在[]中的任意一个原子
| -> 或运算,匹配|符号左右两边的任意一个
[^ ] ->首先这里^必须和[紧挨着,才表示匹配除了[]里面任意原子的字符
[ ^ ]->如果不挨着,就只表示匹配^这种字符了

原子的集合:

  1. . 匹配除换行符之外的任意字符。等价于[^\n]。
  2. \d 匹配任意一个十进制数字,即[0-9]。
  3. \D 匹配任意一个非十进制数字,即[^0-9]。
  4. \s 匹配一个不可见原子,即[\f\n\r\t\v]。
  5. \S 匹配一个可见原子,即[^\f\n\r\t\v]。
  6. \w 匹配任意一个数字,字母或下划线,即[0-9a-zA-Z_]。
  7. \W 匹配任意一个非数字,字母或是下划线,即[^0-9a-zA-Z_]。

量词:

  1. {n} 表示其前面的原子恰好出现n次。
  2. {n,} 表示其前面的原子最少出现n次。
  3. {n,m} 表示其前面的原子最少出现n次,最多出现m次。
    • 匹配0次,1次,或者多次其之前的原子,即{0,}。
    • 匹配1次,或者多次其之前的原子,即{1,}。
  4. ? 匹配0次,1次,或者1次其之前的原子,即{0,1}。

备注:量词不仅支持原子,同样支持原子的集合,同样支持元字符的写法。例如:\w{4}

边界控制与模式单元:

边界控制:

  1. ^ 匹配字符串开始的位置
  2. $ 匹配字符串结尾的位置
    模式单元
  • ()匹配其中的整体为一个原子
    例如:(H|h)ello则匹配Hello和hello的结果。

修正模式

比较重要的两个修正模式:

贪婪匹配
匹配结果存在歧义时取其长
懒惰匹配
匹配结果存在歧义时取其短

其实就是在当匹配结果出现歧义的时候进行修正,默认的修正模式是贪婪匹配。
懒惰模式的标识为大写的U
例如:

$pattern = '/hello.+12/';
$subject = 'hello__1231321233123131';

在贪婪模式下匹配的结果为:hello__1231321233123131
而修改为懒惰匹配

$pattern = '/hello.+12/U';
$subject = 'hello__1231321233123131';

那么结果就会变为:hello__12

常见的修正模式:

  • U 懒惰匹配
  • i 忽略英文字母大小写
  • x 忽略空白(空格,制表符等空白符)
  • s 让元字符’.’匹配包括换行符在内的所有字符
  • e 后面单独写下~

如果想同时使用两种修正模式,写法可以如下:

$pattern = '/helLo/Ui';

常见正则表达式练习

  1. 非空:
    /.+/
  2. 浮点数匹配
    /\d+.\d{2}$/
    实现保留两位的浮点数,$符号是上文中的边界控制哦~
  3. 手机号匹配
    /1[34578]\d{9}/
    匹配到的为1开头,第二位为3,4,5,7,或8的11位手机号
  4. email地址匹配
    /^\w+(.\w+)*@\w+(.\w+)+$/ (\w 字母,数字,下划线)
  5. URL匹配
    http是否出现,是http还是https。即
    ^(https?://)?。
    是否是二级域名? 即:
    (\w+.)+。
    顶级域名。即:
    [a-zA-Z]+。
    故:正则表达式:
    ^(https?://)?(\w+.)+[a-zA-Z]+$

实战:正则工具类的设计实现

话不多说,直接上代码吧~

<?php
class RegexTool {
    //常用的regex表达式数组
    private $validata = array(
        'require'   =>  '/.+/',
            'email'     =>  '/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/',
            'url'       =>  '/^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/',
            'currency'  =>  '/^\d+(\.\d+)?$/',
            'number'    =>  '/^\d+$/',
            'zip'       =>  '/^\d{6}$/',
            'integer'   =>  '/^[-\+]?\d+$/',
            'double'    =>  '/^[-\+]?\d+(\.\d+)?$/',
            'english'   =>  '/^[A-Za-z]+$/',
            'qq'        =>    '/^\d{5,11}$/',
            'mobile'    =>    '/^1(3|4|5|7|8)\d{9}$/',
        );
    //返回数组还是返回真假的boolean变量
    private $returnMatechResult = false;
    //修正模式
    private $fixmode = null;
    //匹配结果数组
    private $matches = array();
    //是否匹配成功
    private $isMatch = false;
    //类的构造函数
    public function __construct($returnMatchResult = false, $fixMode = null) {
    $this->returnMatchResult = $returnMatchResult;
    $this->fixMode = $fixMode;
   }
   //核心匹配方法
   public function regex($pattern ,$subject){
       //array_key_exists判断键值是否存在
        if (array_key_exists(strtolower($pattern), $this->validata)) {
            $pattern = $this->validata[$pattern].$this->fixmode;
        }
        $this->returnMatchResult?
        preg_match_all($pattern, $subject, $this->matches):$this->isMatch = preg_match($pattern, $subject)===1;
        return $this->getRegexResult();
   }
   //获取返回值类型的方法
   private function getRegexResult(){
           if ($this->returnMatchResult) {
               return $this->matches;
           }else{
               return $this->isMatch;
           }
   }
   //切换返回值类型
   public function togoReturnType($boolean = null){

           if (empty($boolean)) {
               $this->returnMatchResult = !$this->returnMatchResult;
           }else{
               $this->returnMatchResult = is_bool($boolean)?$boolean:(bool)$boolean;
           }
   }
   //设定修正模式
   public function setFixMode($fixMode) {
    $this->fixMode = $fixMode;
   }
   //一些数据验证方法

   //是否为空
   public function noEmpty($str){
        return $this->regex('require',$str);
   }
   //验证email
   public function isEmail($email){
       return $this->regex('email',$email);
   }
   //....其他的类似,省略了,小伙伴自己可以自定义添加哦~

   //用户自定义正则表达式
   public function check($pattern, $subject) {
    return $this->regex($pattern, $subject);
    }
}
?>

这个工具已经自己调试过了,如果有问题可以在下面评论交流哦~,欢迎提出改进方案(●ˇ∀ˇ●)
另外上述正则表达式有小伙伴有更好的改进意见的也欢迎交流~(●ˇ∀ˇ●)

ps:对于正则表达式的学习暂时先告一段落了,如果有时间会结合网上的教程自己撸一个简易的Smarty模板引擎,当然只是简易的,届时会在php的分类板块下更新,欢迎小伙伴阅读~
最后感谢慕课网上的相关教程和网上各位大牛的博客和文章,虽然不能一一贴出链接,但谢谢你们的分享。
加油~