概述:
正则表达式,又称规则表达式。是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。
正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
它最初是科学家对人类神经系统工作原理的早期研究(一种用数学方式来描述神经网络的新方法)。
Unix的主要发明人 Ken Thompson 将它运用到了计算搜索算法、编辑器qed、编辑器ed(太古老了),从此被广泛应用
那么它有啥用?
它能帮你在一大堆杂乱无章的内容中,找到符合特定模式的内容
比如,爬取其它网站的内容并提取有用信息;内容关键字审核;特定文本内容整体替换
这一节将介绍一下正则表达式的一些特殊字符和简单用法
在讲这些字符/符号的时候,我会用 php 来举一些例子,基本上所有语言的正则表达式都大同小异,若你使用的是其它语言,也可直接把表达式拿去使用试试
一、特殊字符(元字符)
特殊字符即在正则表达式中有特定含义的内定字符。就好比 java,php 等语言中的关键字
1、$
匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n' 或 '\r'
例子1$s = 'abcd
efd';
preg_match('#[a-z]+?d$#s',$s,$m);//# # 之间的内容为正则表达式,s为修饰符,# 为php中的边界符号,还有 / 也是边界符
print_r($m);//$m 就是我们匹配到的信息
/*
Array
(
[0] => efd
)
*/
匹配以 d结尾(d$) 的一串字符,前面可以是任意a到z 的小写字母([a-z]+?), 其中 s 为修饰符(后面会讲),就是多行模式(Multiline),
所以匹配到了第二行的 efd(因为[a-z]+?不匹配换行),若要匹配整个换行的字符串,则:#([a-z]|\r\n)+?d$#s
2、( )
标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用
例子2$s = 'abc123def456';
preg_match_all('#(\d+)#',$s,$m);
print_r($m[1]);
/*
Array
(
[0] => 123
[1] => 456
)
*/
匹配并捕获字符串中的所有数字,$m[1] 就是捕获到的内容,关于捕获后的使用,将在下面的 \ 符号介绍
\d 等价于 [0-9],关于 [] 字符集下面会讲,只要知道 \d 是表示匹配一个数字就行了
3、+
匹配前面的子表达式一次或多次
见例子2
4、*
匹配前面的子表达式零次或多次
见例子2
5、.
匹配除换行符 \n之外的任何单字符
例子3$s = <<
test!@#$
TEXT;
preg_match_all('#.#s',$s,$m);
print_r($m);
/*
Array
(
[0] => Array
(
[0] => t
[1] => e
[2] => s
[3] => t
[4] => !
[5] => @
[6] => #
[7] => $
)
)
*/
6、[ ]
标记一个中括号表达式字符集合
请看例子1,[a-z] 就是一个字符集合,可以是任意字符,比如我只要匹配 【abc,.】 这个5个字符——[abc,.]
这里有一个特殊的符号 - ,代表一个范围,常用的有 A-Z(大写的字母A到Z),a-z(小写的字母a到z) ,0-9(数字0到9)
7、?
匹配前面的子表达式零次或一次,或指明一个非贪婪限定符
例子4$s = <<
a1a2abbb
TEXT;
//匹配以a开头后面紧跟一个数字或没有数字(用了 ? )的字符串
preg_match_all('#a\d?#',$s,$m);
print_r($m);
/*
Array
(
[0] => Array
(
[0] => a1
[1] => a2
[2] => a
)
)
*/
8、\
将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。
比如匹配在正则中有特殊含义的字符,如 . 、 \ 、 $ 、 ( 、 [ 等等,这里就讲一下 向后引用(反向引用)
例子5$s = <<
this is bthis is i
TEXT;
preg_match_all('#(.+?)\1>#i',$s,$m);
echo "
 
 
";
 
 
print_r($m);
echo "
"; 
 
/*
Array
(
[0] => Array
(
[0] => this is b
[1] => this is i
)
[1] => Array
(
[0] => b
[1] => i
)
[2] => Array
(
[0] => this is b
[1] => this is i
)
)
*/
我想匹配标签 b 和 i (或者其它标签)中的内容,总不能为了每一个标签都写一个表达式吧,比如这个:#(.+?)|(.+?)#i;那么多标签不得写死啊
而标签开头和结尾都是一样的,那么把匹配到的开始标签引用到结束位置不就行了?!
还记得例子2中 () 的作用吗,捕获匹配到的内容,供后面使用。而 \1 就是使用第一个 ( 开始所匹配到并被捕获的内容。在这个例子里 \1 就是匹配到的 b 或 i
那么想一想,若是在 () 中还有 (),如何使用反向引用?
好吧,不用你们想了,我来公布答案。
不管表达式中有多少个 (),都是以 ( 为顺序(从1开始),放在捕获的区域以供后面使用,最多好像是支持 99 个,没试过
在正则表达式中使用之前匹配并捕获(反向引用)的内容就是用 \1 \2 \3 ....各语言可能不同,比如 js 是 $1 ,java 是 \\1
例子6$s = <<
 
 
this is b
 
 
 
  this is span 
 
 
 
this is i
TEXT;
preg_match_all('#(.+?)\2>\1>#i',$s,$m);
print_r($m);
/*
Array
(
[0] => Array
(
[0] => 
 
 
this is b
 
 
[1] => this is i
)
[1] => Array
(
[0] => div
[1] => span
)
[2] => Array
(
[0] => b
[1] => i
)
[3] => Array
(
[0] => this is b
[1] => this is i
)
)
*/
匹配外层是多字符标签(div span 等)包裹,内层紧跟一个字符的标签(b i 等),因为 ([a-z]) 后面没有跟 + ,说明是匹配一个字符
由于
 
 
 
  this is span 
 
 不满足内层一个字符的标签,所以没有被匹配 
 
例子7 java 版import java.util.regex.*;
public class Test {
public static void main(String[] args) throws Exception {
String str = "
 
 
this is b
 
 
 
  this is span 
 
 
 this is i"; 
 
Matcher m = Pattern.compile("(.+?)\\2>\\1>").matcher(str);while(m.find()){
System.out.println(m.group()+"\n"+m.group(1)+"\n"+m.group(2)+"\n开始位置 : "+m.start()+" \n结束位置 : "+m.end()+"\n\n");
}
}
}
输出
 
 
this is b
 
 
div
b
开始位置 : 0
结束位置 : 27
this is i
span
i
开始位置 : 63
结束位置 : 92
9、^
匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合
例子8$s = <<
1abc
TEXT;
//2def
//ght
//34xyz
preg_match_all('#^\d[^\d]+#',$s,$m);
echo "
 
 
";
 
 
print_r($m);
echo "
"; 
 
/*
Array
(
[0] => Array
(
[0] => 1abc
)
)
*/
匹配以一个数字开头后面紧跟非数字的字符串,这个例子就把 ^ 的两个概念都讲了,例子的结果就是能匹配 1abc,2def,不能匹配 ght,34xyz
这里讲讲为什么不能匹配 34xyz,因为 3 被 \d 匹配了,而 4 就只能被 [^\d]+ 匹配,但是这个集合只匹配非数字字符串,所以不满足要求,整个字符串都不能被匹配
在一个字符集中用 ^ (一定要在字符集的开始位置),如 [^abc] ,那么就表示,不匹配abc这三个字母
10、{ }
标记限定符表达式的开始
这个将在限定符一节中将,简单来说就是表示一个范围
11、|
指明两项(多项)之间的一个选择
例子9$s = <<
this is bthis is ithis is span
TEXT;
preg_match_all('#(.+?)\1>#',$s,$m);
print_r($m);
/*
Array
(
[0] => Array
(
[0] => this is b
[1] => this is i
)
[1] => Array
(
[0] => b
[1] => i
)
[2] => Array
(
[0] => this is b
[1] => this is i
)
)
*/
匹配 b 或者 i 标签包裹的内容,若也要匹配 span, 加上即可,#(.+?)\1>#
特殊字符暂时就介绍这些,单个的字符都很好理解,但想写出复杂的正则表达式却无从下手。
那么如何构造复杂的表达式?
简单来说就是化整为零,正则表达式可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些符号的任意组合。
用多种元字符(特殊字符)与操作符将小的表达式结合在一起来创建更复杂的表达式。
比如 例子5 就用了很多元字符
一定要多练,才能把所有符号牢记于心,都是熟能生巧。
布置一个练习题
待匹配内容
 
 

   123abc, 
 
 
 
456def
a1b2c3
请匹配出 456def
分析下:
1、外面包裹的标签不一定是这几个(div span m)
2、内容是以 数字开头的,后面跟个几个字母
很简单,看上面的几个例子,动动手就可以完成
下一节讲 限定符和符号的运算优先级