正则对于新人来说是一个头疼的名字,让人闻而生畏。但是,在我看来,正则,并没有那么神秘,希望能通过这篇正则表达式入门教程解除正则新人对于正则的畏惧感。
内容导航
定锚点,去噪点,取数据
一、入门:正则字符
- . 匹配不包括换行的任意字符
- s 空格、tab、换行
-
- 匹配零个或更多个,即0~n
-
- 匹配一个或更多个,即至少一个,1~n
- 转义
- [] 单字符取一个,比如[abc]会匹配a或b或c
- ^ 字符串开始
- $ 字符串结束
- {1,3} 循环次数
- ? 有两个用法
(1) 匹配一个或零个
(2)非贪婪模式 - | 多个数据选一(常用于多字符)
- () 数据分界和取数据
- (?:) 非捕获组
- 分隔符
- 模式修饰符
二、 操作:定锚点
总结:锚点,就是能唯一定位你数据的标识
三、 操作:去噪点
总结:关心的留下,不关心的都是浮云
四、 操作:取数据
总结:子模式计数,数左括号从1开始,排除非捕获组的左括号
五、正则表达式高级教程
先概括一下,正则三段论:
定锚点,去噪点,取数据
一、入门:正则字符
关于正则字符,很多文章都会讲到,足足有一篇文章才能描述清楚,我这里就不多说,对于我,平时,常用的有:
- . 匹配不包括换行的任意字符
在php的s修饰符(单行模式)下面可以匹配换行,如$pattern='#(.*?)#s';就可以匹配div内容有换行的数据。
如果需要匹配包括换行的任意字符,可以使用[sS]代替.
- s 空格、tab、换行
[sS]表示匹配任意字符,S是s的反义。
注意区分[sS]与.的区别。 -
- 匹配零个或更多个,即0~n
-
- 匹配一个或更多个,即至少一个,1~n
-
转义
一个特殊字符前加就表示转义,说明把它当普通字符用 -
[] 单字符取一个,比如[abc]会匹配a或b或c
但是,如果[]里面加上^则会变成排除这个字符,如[^abc]就表示不是a、不是b、也不是c
另外,在[]里面可以使用-表示一个范围,如[0-9]表示从0到9,类似的还有[a-zA-Z],如果要包含-字符,可以给它加上转义[-]。
关于[]常见的错误用法是:[ab|bc]用来表示ab或bc,实际上,它得到的结果是[abc|],即a或b或c或|这4个字符(单字符)的任意一个。这里可以改成(ab|bc)。
总结:[]里面的特殊符有五个:[]-^,其他字符都是普通字符,包括*.?等。
说明:- ^在[^ 的首位时候才有特殊意义
- [0-9 -在不是首尾的时候有特殊意义
- [ ] 因为占用[] 本身字符,所以有特殊意义
- 本身是转义符,有特殊意义
-
^ 字符串开始
这里的^跟[]里面用的^是同一个字符,但是却不是一个意思,这里它表示整个字符串的开始,比如^www表示以www开头的字符串,注意区分,不在[]里面的是开始符,在里面的排除 - $ 字符串结束
-
{1,3} 循环次数
[0-9]{1,3}表示在0-9的范围里面循环1个、2个或者3个,可能结果有5、20、415等。
如果循环指定次数,如3次,则{3,3}可以简写成{3}。
如果刚好需要匹配字符{1},则正则需要给{进行转义,得到{1}的正则。
如果{}中间不是数字,则{}本身不需要转义。 - ? 有两个用法
(1) 匹配一个或零个
比如https?匹配的https(一个s)或者http(零个s)
(2)非贪婪模式
所谓非贪婪模式,就是匹配尽可能少的内容,比如,对于源字符串
ab
使用(.*?)会得到2个结果(注意:如果源字符串有换行,使用[sS]替换 . ):
a
和
b
因为,当遇到第一个,非贪婪模式就不会再往后找了。
而使用(.*)(贪婪模式)则会得到整个字符串
ab
,因为它会匹配所有字符直到后面再找不到。
更多关于?的使用,可以参考《正则表达式匹配次数》
- | 多个数据选一(常用于多字符)
前面提到[]里面的字符有选一个字符功能,但是假如不是一个字符,比如:http|ftp|svn 就需要用|分开,|的作用域是一直往后直到遇到括号,比如,对于源字符串
http abc
ftp abc
svn abc
http|ftp|svn abc匹配的结果是:
http
和
ftp
和
svn abc
想要匹配 http abc和ftp abc和svn abc就要使用括号把前边的协议括起来,如(http|ftp|svn) abc 可以得到预期的结果。
-
() 数据分界和取数据
上面例子(http|ftp|svn) abc就是数据分界的例子,然后,匹配结果会得到一个1的子集数据(数组下标1),这里就是子模式的概念,子模式也叫分组,利用子模式,可以得到想要取出来的数据。子模式1、2、3的计算方法为左括号的计数,从左到右,从1开始,比如:
(http|ftp|svn)://([^/]+),分组1得到的是(http|ftp|svn)里面的数据,分组2得到([^/]+)里面的数据,对于嵌套括号也是点左括号即可。在正则中有很多与括号结合的写法,你在数左括号的时候,一定要注意,非捕获组和环视的左括号都是不需要数的。
在使用子模式过程中,常见两种写法是:1 和 $1。
(1) 1 是在正则表达式本身中引用分组1的内容,如:
我们要匹配111这样的连续出现3此的数字,我们可以写出正则:(d)11,(d)匹配到第一个1,后面再引用这个匹配内容,得到111。
(2) $1 是在替换中调用分组的内容,如:
我们要替换链接参数name=Zjmainstay为username=Zjmainstay,我们可以使用正则name=([^&]+)替换为username=$1来实现,这里的$1就引用了分组1的结果Zjmainstay,因此得到我们想要的结果。 -
(?:) 非捕获组
上面说到()作为子模式可以得到它里面的数据,但是,有些时候,()只是作为数据分界功能,并不需要取出来,这时候就要用到非捕获组的概念了。比如:(http|ftp|svn)://([^/]+)只想得到域名,也就是[2],那么(http|ftp|svn)就只是数据分界的功能,这里不需要捕获,因此使用非捕获组功能,(?:http|ftp|svn)屏蔽这部分的数据获取,此时,(?:这个左括号排除1计数,也就是(?:http|ftp|svn)://([^/]+)中的([^/]+)变成1了。 - 分隔符
在一些语言中,你会发现正则第一个和最后一个字符是相同的,如:
/d+/
这个/ /在PHP中称为分隔符,正则表达式需要由分隔符闭合包裹。在PHP中,分隔符可以使任意非字母数字、非反斜线、非空白字符。这个概念很关键,它能帮助我们简化一些正则的书写,避免错误,如:
/.*?/
这个正则是错误的。
原因是的/与分隔符相同,但是却没有做转义。
如下程序:
preg_match('/.?/', 'abc', $match);
PHP中会收到错误提示:Warning: preg_match(): Unknown modifier 'd' in regexTest.php on line 2
对于这种情况,有两种解决方案:
(1)/.?