闭包回顾
有一个东西,就是因为它,使得它所在的作用域不被释放,它是就是闭包。
目标
- 1、能够掌握正则表达式的语法(涉及到的内容,最起码会查手册)
- 2、能够理解什么是捕获和引用
- 3、能够匹配中文
- 4、能够查阅正则对象中内置的方法
- 5、能够查阅字符串对象中支持正则的方法
- 6、能够在PHP中使用正则
一、概述
w3c手册位置:上面的JavaScript — 左侧的JavaScript — 右侧的参考书 — 左侧的JS RegExp
或者:上面的JavaScript — 右侧的JavaScript — 左侧的JS RegExp
1、概述
正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个字符串中是否含有某种子串、将匹配的子串做替换或者从某个字符串中取出符合某个条件的子串等。
匹配就是在某个字符串中查找你想要查找的内容(由正则表达式决定),如果查找到了,就表示匹配。没有查找到就表示不匹配。
正则表达式本身是一门独立的技术,可以被大多数编程语言所使用,如Javascript、PHP、Java…
正则表达式也是用于查找字符串的,只是比正常的查找更加高级。
比如在字符串“abacad”中查找a:
JavaScript语法:
'abacadabacad'.search('a');
php语法:
strpos('abacad', 'a');
如果查询条件是下面的条件,用普通的查询就不能完成了。
要求查找a,什么样的a呢?后面必须是b的a。这正是正则表达式的用武之地。
2、应用场景
(1)表单验证里面,验证字符的合法性,如邮箱是否合法,手机号是否合法等等。
(2)信息过滤,如论坛帖子或者评论中的非法字符,例如 sql注入、js脚本注入、煽动性的言论。
(3)信息采集,采集别人网站上面的内容,例如整页采集时 筛选出需求的部分。
(4)信息替换。
(5)页面伪静态的规则。
二、入门案例
1、正则用法说明
//查询字符串str中是否含有h
var str = 'phphp';
//var result = str.match('h'); //说明match是一个字符串对象中的一个方法
var result = str.match(/h/g); //正则语法,要求用斜线当做正则表达式的起始和结尾的标识符
console.log(result); //查询到了,返回一个包含h的数组
输出结果:
没匹配的情况:
没有匹配,返回null。
2、全局修饰符g
g是global,表示全局的意思,它是正则表达式语法中的修饰符,修饰符应该放到定界符(/)的后面。
输出结果:
三、正则语法
1、量词
n+ 匹配任何包含至少一个 n 的字符串。匹配一个或多个前导字符(前导字符就是紧挨着+的前一个字符)
var str = 'php phhhhhp pp phhp phhhhp phhhp phhap';
var result = str.match(/ph+p/g);// + 表示至少有一个前导字符。前导字符是符号前面的一个字符
n* 匹配任何包含零个或多个 n 的字符串。前导字符有没有都行
n? 匹配任何包含零个或一个 n 的字符串。
n{X} 匹配包含 X 个 n 的序列的字符串。
n{X,Y} 匹配包含 X 到 Y 个 n 的序列的字符串,包括X和Y个
n{X,} 匹配包含至少 X 个 n 的序列的字符串。
var str = 'php phhhhhp pp phhp phhhhp phhhp phhap';
var result = str.match(/ph*p/g); // * 表示前导字符个数不限
var result = str.match(/ph?p/g); // ? 表示0 个或1 个前导字符
var result = str.match(/ph{2}p/g); // {2} 表示前导字符串必须是2 个
var result = str.match(/ph{2,}p/g); // {2,} 表示前导字符串至少是2 个
var result = str.match(/ph{2,4}p/g); // {2,4} 表示前导字符串是2~4 个(包含2和4)
n 匹配任何开头为 n 的字符串。(注意位置在字符串最前面)
^n ^匹配任何开头为 n 的字符串。(注意位置在字符串最前面)
n$ 匹配任何结尾为 n 的字符串。从末尾开始匹配
n$ 表示只匹配字符串n。也就是匹配整个字符串。
^n$ 表示只匹配字符串n。也就是匹配整个字符串。
var str = 'php is very good, this is a phhhhhhhhp';
var result = str.match(/^php/g); // ^ 表示从字符串的开头开始匹配,检测字符串的开头是不是php
var result = str.match(/ph*p$/g); // $ 表示匹配字符串的结尾
var str = 'php';
var result = str.match(/^php$/g); // ^php$ 表示只匹配php,任何其他都不匹配。这种形式表示匹配整个字符串
// ^ph+p$ 表示匹配整个字符串,要求整个字符串开头必须是p,结尾必须是p,中间必须是至少一个h,而不能有其他字符
var str = 'phhhhhpp';
var result = str.match(/^ph+p$/g);
console.log(result);
2、元字符
. 表示单个字符,表示任意字符。除了换行和行结束符。
.* 表示任意字符串(0个或多个任意字符,除了换行和行结束符).是任意一个字符,*表示任意个前导字符。二者组合表示任意字符串
var str = 'php';
var result = str.match(/p.p/g); // . 表示任意字符,一个点只表示一个字符
var str = 'phahsp';
var result = str.match(/p.*p/g); // .* 表示任意字符串
\w 匹配任何数字、字母、下划线。一个\w表示一个字符。
\W 匹配任何非数字、非字母、非下划线。
var str = 'pha_Asp';
var result = str.match(/p\w*p/g); // \w 表示一个数字、字母、下划线
var str = 'p -*#.p';
var result = str.match(/p\W*p/g); // \W 表示一个非数字、非字母、非下划线
\d 查找数字。
\D 查找非数字字符。
var str = 'hello123456abc789';
var result = str.match(/\d/g); // \d 表示一个数字
var result = str.match(/\d+/g); // \d 表示一个数字
var result = str.match(/\D/g); // \D 表示一个非数字
\s 查找空白字符。
\S 查找非空白字符。
var str = 'how are you';
var result = str.match(/\s/g); // \s 表示一个空格
var result = str.match(/\s+/g); // \s 表示一个空格
\b 匹配单词边界。(边界字母个数没有限制;\b放前面表示匹配单词前面的边界,\b表示匹配单词后面的边界)
\B 匹配非单词边界。
var str = 'abcd nihao how ar you';
var result = str.match(/\bh/g); // \b 表示匹配单词的边界,\b放到前面表示-匹配前面的边界,\b放到后面表示匹配后面的边界
var result = str.match(/\ba/g);
var result = str.match(/\babc/g);
var result = str.match(/o\b/g); // \b 判断o是不是单词的结尾
var result = str.match(/\byou\b/g); // \byou\b 只匹配单词you
\n 查找换行符。
\r 查找回车符。
\t 查找制表符。
var str = 'this is a php.\nthat is a javascript';
var result = str.match(/\n/g);
//alert(str);
console.log(result);
3、方括号
方括号表示一个范围,也称为字符簇。
[abc] 查找方括号之内的任何字符。
[abc] 查找任何不在方括号之间的字符。(方括号中的表示取反)
[^abc] 查找任何不在方括号之间的字符。(方括号中的^表示取反)
var str = 'hello world';
//一个方括号表示一个字符 [woxd]意思是在字符串中查找w或o或x或d
var result = str.match(/[woxd]/g); //["o", "w", "o", "d"]
var result = str.match(/[^woxd]/g); //表示排除woxd,查询其他字符,结果:["h", "e", "l", "l", " ", "r", "l"]
[0-9] 查找任何从 0 至 9 的数字。表示一个字符
[a-z] 查找任何从小写 a 到小写 z 的字符。
[A-Z] 查找任何从大写 A 到大写 Z 的字符。
[A-z] 查找任何从大写 A 到小写 z 的字符。包括下划线。
[a-z0-9A-Z]查询所有的字母和数字
[5-8] 查找5 <= 目标 <= 8的字符
(red|blue|green) 查找任何指定的选项。(竖线|表示或者)
(\s+)|(\s+$)匹配字符串前后的空格
var str = 'php7 and ES6_';
var result = str.match(/[a-z]/g); //只查找小写字母
var result = str.match(/[c-m]/g); //只查找c~m范围内的小写字母 结果: ["h", "d"]
var result = str.match(/[A-Z]/g); //查找大写字母
var result = str.match(/[0-9]/g); //查找数字
var result = str.match(/[A-z]/g); //查找大小写字母和下划线
var result = str.match(/[a-z0-9A-Z]/g); //查询所有的字母和数字
var result = str.match(/[0-9]|[a-z]/g); //查询所有的字母和数字
var str = ' hello world ';
var result = str.match(/(^\s+)|(\s+$)/g); //匹配字符串前后的空格
console.log(result);
4、修饰符
修饰符的用法,是修饰符一定要写到//之后,可以一次性使用多个修饰符。
i 执行对大小写不敏感的匹配。实际上就是不区分大小写的匹配
g 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
m 执行多行匹配。
var str = 'phppHpphp';
var result = str.match(/h/g);
var result = str.match(/h/ig); // 表示不区分大小写的查找所有的h
var str = 'this is a php\nthat is a JS';//添加了换行
//alert(str);
var result = str.match(/php$/gm); //m 表示执行多行识别匹配
console.log(result);
5、转义字符\
如果匹配的字符串在正则中有特殊含义的都必须加转义字符。如
[]$.*?+|^{}()
但是不要乱加转义。
var str = 'this book is $3.';
var result = str.match(/\$/g); // 表示匹配$ 符号,而不是从结尾匹配的意思
var result = str.match(/b/g); // 不要加斜线,表示匹配字符b
console.log(result);
四、分组/捕获和反向引用
捕获和反向引用的语法的解释:
正则中出现的小括号,就叫捕获或者分组
小括号捕获,\1引用
在正则语法中(在/…/内),在捕获的后面,用“\1”来引用前面的捕获。用\2表示第二个捕获的内容….
在正则语法外(如replace时),用“$1”来引用前面的捕获。
var str = '1122 3434 5678 9090 1516';
//要求:匹配连续的4个数字
var result = str.match(/\d{4}/g);
var result = str.match(/[0-9]{4}/g);
var result = str.match(/\d\d\d\d/g);
//要求:匹配连续的4个数字。要求第1个数字和第3个数字相同
var result = str.match(/(\d)\d\1\d/g);
//要求:匹配连续的4个数字。要求第1个数字和第3个数字相同,并且第2个数字和第4个数字相同
var result = str.match(/(\d)(\d)\1\2/g);
//要求:匹配连续的4个数字。要求第1个数字和第2个数字相同,第3个和第4个相同
var result = str.match(/(\d)\1(\d)\2/g);
//禁止引用
var result = str.match(/(\d)(?:\d)\1\d/g);
console.log(result);
禁止引用
(?:正则) 这个小括号中的内容不能够被引用
//禁止引用
var str = '1122 3434 5678 9090 1516';
var result = str.match(/(\d)(?:\d)\1\d/g);//捕获的时候加入?:,表示这个小括号里面的内容不能被\2引用
console.log(result);
五、匹配中文(utf-8编码)
每个字符(中文、英文字母、数字、各种符号、拉丁文、韩文、日文等)都对应着一个Unicode编码。
查看Unicode编码,找到中文的部分,然后获取中文的Unicode编码的区间,就可以用正则匹配了。
前面我们用[a-z]表示小写字母,[0-9]表示数字,这就是一个范围表示,如果有一个数x能够表示第一个中文,有一个数y能够表示最后一个中文,那么[x-y]就可以表示所有的中文了。
中文的Unicode编码从4E00开始,到9FA5结束。
[4E00-9FA5]这个区间就能够表示中文。
JS语法:
[\u4e00-\u9fa5]// \u 表示后面的是unicode编码
完整的Unicode编码表:http://blog.csdn.net/hherima/article/details/9045861
php匹配中文
$str = 'nihao, 中国';
//preg_match_all(正则表达式, 匹配的字符串, 匹配的内容); //该函数和JS中的match一样
preg_match_all('/[\x{4e00}-\x{9fa5}]/u', $str, $out);
echo '<pre>';
print_r($out);
六、环视(断言/零宽断言/正向预测/负向预测)
every(?=n) 匹配任何其后紧接指定字符串 n 的字符串。
有一个字符串是“abacad”,从里面查找a,什么样的a呢?后面必须紧接b的a。
正则语法是:
/a(?=b)/g
延伸一下,案例中的a、b都是正则表达式,实际上换一个复杂一点的正则表达式也是可以的。
var str = 'abacad';
var result = str.match(/a(?=b)/g);
var str = 'php7 and ES5 hello中国';
//查询连续的字母,要求字母的后面必须是数字
var result = str.match(/[a-zA-Z]+(?=\d)/g);
//查询连续的字母,要求字母的后面必须是数字或者是中文
var result = str.match(/[a-zA-Z]+(?=\d|[\u4e00-\u9fa5])/g);
console.log(result);
```
###every(?!n) 匹配任何其后没有紧接指定字符串 n 的字符串
有一个字符串是“abacad”,从里面查找a,什么样的a呢?后面不能紧接b的a。
正则语法是:
```js
/a(?!b)/g
(?!B)[A-Z][A-Z]范围里,排除B的
另外,还会看到(?!B)[A-Z]这种写法,其实它是[A-Z]范围里,排除B的意思,前置的(?!B)只是对后面数据的一个限定,从而达到过滤匹配的效果。
/*********** (?!n) *************/
var str = 'abacad';
var result = str.match(/a(?!b)/g);
console.log(result);
/*********** (?!B)[A-Z] *************/
var str = 'ABCDEFG'; //
var result = str.match(/(?!B)[A-Z]/g); //["A", "C", "D", "E", "F", "G"]
var result = str.match(/(?![C-E])[A-Z]/g); //排除C-E ["A", "B", "F", "G"]
var str = '12421asdfASDF';
//下面的例子,表示整个字符串可以由数字、字母组合,但是不能是纯数字
var result = str.match(/(?!^\d+$)^[0-9a-zA-Z]+$/g); //
console.log(result);
七、正则对象的属性和方法
正则对象中的成员方法和属性的正确调用方式:
和String对象类似:
一种是直接量语法
(/[a-z]/.exec())
另一种方法是实例化正则对象,然后通过对象去调用成员方法
(var reg = new RegExp(/[a-z]/); reg.exec())
类似字符串:
'hello'.substr(1);
var s = new String('hello'); s.substr(1);
/** 直接量语法,直接使用正则表达式调用正则对象的方法 **/
//检测正则表达式的匹配,如果匹配返回true,失败返回false
var str = '12312412';
var r = /^\d+$/g;
//正则对象的方法,由正则对象来调用。
var result = r.test(str);//test()方法为正则对象方法 jian ce
var result = /^\d+$/g.test(str);
console.log(result);
/** 先创建正则对象,然后使用对象去调用正则方法 **/
var reg = new RegExp(/^\d+$/, 'gi');//‘gi’修饰符
var str = '12312412';
var result = reg.test(str);
console.log(result);
直接量语法:只能写两条斜线的形式。
实例化正则对象:可以写两条斜线的形式,也可以写字符串的形式。
1、exec方法和lastIndex属性
exec方法执行一个正则匹配,只匹配一次,匹配到结果就返回一个数组类型的结果,匹配不到就返回null。并将表示匹配的位置 置为下一个匹配的位置。
lastIndex一个整数,标示开始下一次匹配的字符位置。没有更多匹配重置lastIndex为0.
依次调用exec匹配下一个的例子:
依次调用exec,会将匹配的位置不断的后移,直至结尾。
匹配带子表达式的例子,带子表达式并且依次调用的例子:
依次调用,依然匹配下一个:
var str = '1122 3434 5677';
var r = /\d\d\d\d/g;
var i = r.lastIndex; //表示下一次匹配的位置,默认从0的位置开始
var result = r.exec(str); //表示匹配的结果,[1122]
console.log(i, result);
var i = r.lastIndex; //表示下一次匹配的位置,默认从0的位置开始
var result = r.exec(str); //表示匹配的结果,[3434]
console.log(i, result);
var i = r.lastIndex; //表示下一次匹配的位置,默认从0的位置开始
var result = r.exec(str); //表示匹配的结果,[5677]
console.log(i, result);
var i = r.lastIndex; //表示下一次匹配的位置,默认从0的位置开始
var result = r.exec(str); //表示匹配的结果,null
console.log(i, result);
/************** 匹配带子表达式的例子,带子表达式并且依次调用的例子 ***************/
var str = '1122 3434 5677 8989 0000';
var r = /(\d)(?:\d)\1\d/g;
var i = r.lastIndex; //开始匹配的位置
var res = r.exec(str);//匹配的结果
console.log(i, res);
var i = r.lastIndex; //开始匹配的位置
var res = r.exec(str);//匹配的结果
console.log(i, res);
2、test方法 经常用在验证手机号 邮箱是否正确
/****************** 直接量语法,直接使用正则表达式调用正则对象的方法 *******************/
//检测正则表达式的匹配,如果匹配返回true,失败返回false
var str = '12312412';
var r = /^\d+$/g;
//正则对象的方法,由正则对象来调用。
//var result = r.test(str);
var result = /^\d+$/g.test(str);
console.log(result);
/****************** 先创建正则对象,然后使用对象去调用正则方法 *******************/
var reg = new RegExp(/^\d+$/, 'gi');
var str = '12312412';
var result = reg.test(str);
console.log(result);
八、支持正则表达式的 String 对象的方法
1、search()
在字符串中搜索符合正则表达式的结果。如果找到结果返回结果的位置,停止向后检索,也就是说忽略全局标识符g;如果没有匹配结果,返回-1.
2、match()
在字符串中检索匹配正则表达式的子串;如果匹配,返回包含匹配结果的一个数组;不匹配返回null。
不加全局g的情况:
获取的结果只是第一个匹配的内容,匹配的内容中的第一个单元是匹配的结果,后面的单元是子表达式
带子表达式的情况:
加全局的g的情况:
获取的结果是所有匹配的内容,但是不包含子表达式。
多次调用和调用一次效果一样。
var str = '1122 3456 7878 9090';
/**************** 没有g ****************/
var r = /(\d)(\d)\1\2/;
var result = str.match(r);
console.log(result);
var result = str.match(r);
console.log(result);
/**************** 有g ****************/
var r = /(\d)(\d)\1\2/g;
var result = str.match(r);
console.log(result);
3、split()
将字符串分割成数组:
特点是可以用正则表达式来分割字符串。
var str = '21423523@qq.com';
var res = str.split('@'); //用字符串分割 ["21423523", "qq.com"]
var res = str.split(/@/); // ["21423523", "qq.com"]
//用 @或者. 来分割邮箱
var res = str.split(/@|\./); // ["21423523", "qq", "com"]
console.log(res);
4、replace()替换
默认只替换一次,加g全部替换。加入全局的g:
替换的时候,使用"$1"表示第一个子表达式:
替换的时候,使用"$1"表示第一个子表达式:
用$2表示第二个子表达式,以此类推。
在正则表达式内部 用/1 /2替换捕获的内容()括号里的,字符串中用$1 $2
捕获的内容左侧的右侧内容
替换abc为a[a-b-c]c ghk g[g-h-k]k
用 $`表示捕获的内容左侧的内容 用$'表示捕获的内容右侧的内容
函数来进行复杂的替换
替换aaa bbb ccc为Aaa Bbb Ccc
<script>
/** 简单的替换 **/
var str = 'hello world';
var result = str.replace('l', 'L'); //字符串替换 heLlo world
var result = str.replace(/l/, 'L'); // heLlo world
var result = str.replace(/l/g, 'L'); //全部替换 heLLo worLd
console.log(result);
/** 使用子表达式 **/
var str = 'abcd123';
//替换成aabbccdd123
var result = str.replace(/([a-z])/g, '$1$1');
console.log(result);
/** 借助子表达式 **/
//替换abc为a[a-b-c]c ghk g[g-h-k]k
var str = 'abc'; // a[a-b-c]c
var result = str.replace(/(b)/g, "[$`-$1-$']");
console.log(result);
/**借助函数**/
//替换aaa bbb ccc为Aaa Bbb Ccc
var str = 'aaa bbb ccc';
var result = str.replace(/[a-z]+/g, function(x){
//需要把替换后的结果返回即可
return x.substr(0,1).toUpperCase() + x.substr(1);
//substr第一个参数表示从什么位置开始,第二个参数表示替换几个,如果只有一个参数,就是从什么位置往后全部替换
//也可以写为
// return x.substr(0,1).toUpperCase() + x.substr(1,2);
});
console.log(result);