2017-08-17 正则浅析

本文只探讨正则在php中的一些使用,小白用户还是先了解下正则相关的基础概念:正则表达式30分钟入门教程

一、正则基础函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
/**
* 函数参数说明
* $pattern = 正则表达式
* $subject = 匹配的目标数据
*
*/
// 只将第一个匹配到的结果赋值给$matches,$matches为一维数组。preg_match返回值为匹配到的次数,0或1.
preg_match($pattern, $subject);
// 将所有匹配到的结果赋值给$matches,$matches为二维数组。preg_match_all返回值为匹配到的次数。
preg_match_all($pattern, $subject, $matches);
// preg_filter()和preg_replace()区别:在对数组方面替换的时候,preg_replace()会返回所有结果,preg_filter()只会返回替换到的结果。
preg_replace($pattern, $replacement, $subject);
preg_filter($pattern, $replacement, $subject);
// 只匹配,不替换,返回匹配到的数组值
preg_grep($pattern, array $input);
// 区别explode(…)
preg_split($pattern, $subject);
// 它会将正则表达式中的特殊字符进行转义。
// regex的运算符: . \ + * ? [ ^ ] $ ( ) { } = ! < > | : -
// 转义符号 \
preg_quote($str)

二、正则表达式基本语法

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

  • 界定符: 表示一个正则表达式的开始和结束;EG:/[0-9]/; eg: $pattern = ‘/[0-9]/‘ 或者 #[0-9]# {[0-9]}(不推荐使用大括号);
  • 原子: 原装可以分为可见原子和不可见原子,都能用正则表达式进行原子匹配。
    • 可见原子:Unicode编码表中用键盘输出后肉眼可见的字符, 比如
      • 标点 _ ;,?等等
      • 英文字母和数字
      • 汉字/日文等其他语言文字
      • 求和等数理化公式符号
      • 其他可见字符
      • 特殊原子:\ 因为本身还是转义字符,所以要用\才能匹配到一个\符号
    • 不可见原子: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次,或者1次其之前的原子,即{0,1}。

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

  • 边界控制
    1. ^ 匹配字符串开始的位置
    2. $ 匹配字符串结尾的位置
  • 模式单元
    • ()匹配其中的整体为一个原子, 例如:(H|h)ello则匹配Hello和hello的结果。
  • 修正模式
    • 贪婪匹配: 匹配结果存在歧义时取其长
    • 懒惰匹配: 匹配结果存在歧义时取其短
    • 常见的修正模式:
      • U 懒惰匹配
      • i 忽略英文字母大小写
      • x 忽略空白(空格,制表符等空白符)
      • s 让元字符’.’匹配包括换行符在内的所有字符
      • e 后面单独写下~

        惰模式的标识为大写的U
        例如:
        $pattern = ‘/hello.+12/‘;
        $subject = ‘hello1231321233123131’;
        在贪婪模式下匹配的结果为:hello
        1231321233123131
        而修改为懒惰匹配

        $pattern = ‘/hello.+12/U’;
        $subject = ‘hello1231321233123131’;
        那么结果就会变为:hello
        12

三、常见正则表达式练习

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

3.1 正则工具类的设计实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?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);
}
}
?>

四、其他语言或ide工具的正则语法使用

4.1 vim下正则使用

vim下的正则使用主要是批量替换的功能,使用语法如::[range]s/from/to/[flags]

vim替换语法

range:搜索范围,如果没有指定范围,则作用于但前行。

  • :1,10s/from/to/ 表示在第1到第10行(包含第1,第10行)之间搜索替换;
  • :10s/from/to/ 表示只在第10行搜索替换;
  • :%s/from/to/ 表示在所有行中搜索替换;
  • 1,$s/from/to/ 同上。

flags 有如下四个选项:

  • c confirm,每次替换前询问;
  • e error, 不显示错误;
  • g globle,不询问,整行替换。如果不加g选项,则只替换每行的第一个匹配到的字符串;
  • i ignore,忽略大小写。

vim中使用的正则表达式语法

这里只针对vim中特殊的正则进行说明,其他的与通用正则大体一致。

  • 元字符: 大体一致,比如\w 代表匹配单词字母,等同于[0-9A-Za-z_]
  • 一些普通字符需转意
    • .: 匹配.字符, 不需要转义
    • \: 匹配\字符, 不需要转义
  • 表示位置的元字符
    • \<: 匹配单词词首
    • \>: 匹配单词词尾

vim 使用范例

  • %s/^\(.\+\)$/,(\1)/ : 缓存变量使用,在vim中用 \num表示;
  • :%s/\n//g: 批量删除换行
  • 删除行尾空格::%s/\s+$//g
  • 删除行首多余空格:%s/^\s*// 或者 %s/^ *//
  • 删除沒有內容的空行:%s/^$// 或者 g/^$/d
  • 删除包含有空格组成的空行:%s/^\s*$// 或者 g/^\s*$/d
  • 删除以空格或TAB开头到结尾的空行:%s/^[ |\t]*$// 或者 g/^[ |\t]*$/d
  • 把文中的所有字符串“abc……xyz”替换为“xyz……abc”可以有下列写法
    • :%s/abc\(.*\)xyz/xyz\1abc/g
    • :%s/\(abc\)\(.*\)\(xyz\)/\3\2\1/g

一些学习工具