喜欢的事用心去做 阅读(80) 评论(0)

经常碰到需要使用正则表达式的情况,总是习惯性地搜索,复制,粘贴,时间久了导致原来还知道一点正则表达式的自己,现在连读一个复杂的表达式都有困难。因此,决定,好好学学正则表达式,这里先从基础开始,在记录几个常见的表达式,练习读正则表达式的能力,另外简单介绍一下JavaScript中的regexp对象。

一、正则表达式简介:

正则表达式:是由普通字符以及特殊字符组成的文字模式,它描述了一种字符串匹配的规则,可以用来检查一个字符串是否包含某个子串,将某个字符串替换或者从字符串中提取出某个子串。构建正则表达式和数学表达式一样,可以将小的表达式组合来构建更大的表达式。

普通字符:普通字符包括没有显示指定为元字符的所有可打印和不可打印字符,这包括所有大写和小写字母,所有数字,所有标点符号和一些其他符号。

非打印字符
非打印字符 说明
\cx  匹配由x指明的控制字符。例如 \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 'c' 字符。
\f  匹配一个换页符。等价于 \x0c 和 \cL。
\n  匹配一个换行符。等价于 \x0a 和 \cJ。
\r  匹配一个回车符。等价于 \x0d 和 \cM。
\s  匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S  匹配任何非空白字符。等价于 [^ \f\n\r\t\v]
\t  匹配一个制表符。等价于 \x09 和 \cI 
\v  匹配一个垂直制表符。等价于 \x0b 和 \cK

特殊字符:一些有特殊含义的字符,如通配符“*”,这些字符如果要在字符串中查找需要使用转义字符,也就是反斜杠\。

通配符
 特殊字符  描述
 $  匹配输入字符串的结尾位置。
 ()  标记一个子表达式的开始和结束。
 *  匹配前面子表达式零次或多次。
 +  匹配前面的子表达式一次或多次。
 .  匹配除换行符\n之外的任何单字符。
 [  标记一个中括号表达式的开始。
 ?  匹配前面的子表达式一次或零次或指明一个非贪婪限定符。
 \  将下一个字符标记为特殊字符、或元义字符、或向后引用、或八进制转义符。
^  匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。
{  标记限定符表达式的开始。
|  指明两项之间的一个选择。

限定符:限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配次数不固定,主要包括{0 or 1},{1 or n},{0 or 1},{n},{大于等于n},{大于等于n,小于等于m}六种。对应表达式分别是*,+,?,{n},{n,},{n,m}。

限定符
限定符 描述
* 匹配前面的子表达式零次或多次。
+ 匹配前面的表达式一次或多次。
匹配前面的子表达式零次或一次。
{n} n是一个非负整数,匹配确定的n次。
{n,} n是一个非负整数,至少匹配n次。
{n,m} m,n是非负整数,n<=m,最少匹配n次,最多匹配m次。注意在“,”和两个数之间不能有空格。

定位符: 定位符能够使我们将正则表达式固定到行首或行尾。同时还可以创建特殊的表达式,例如:正则表达式出现在一个单词内或者一个单词开头或一个但多次结尾。定位符用来描述字符串或者单词的边界。

定位符
字符 描述
^ 匹配输入字符串的开始位置。如果设置RegExp为Multiline属性,还可以与\n和\r之后的位置匹配。
$ 匹配输入字符串结尾的位置。如果设置RegExp为Multiline属性,还可以与\n和\r之后的位置匹配。
\b 匹配一个字边界,即字与空格间的位置。
\B 非字边界匹配。

注意:不能将限定符与定位点一起使用,由于在靠近换行或者字边界的前面或后面不能有一个以上的位置,因此不允许“^*之类的表达式”。

若要匹配一行文本开始处的文本,应该将^置于正则表达式开始;若要匹配一行文本结尾处的文本,则在正则表达式的结尾处使用$。不要将 ^ 或者$的这种用法与中括号表达式内的用法混淆。

eg:

/^Chapter [1-9][0-9]{0,1}/匹配章节标题为两位数的以Chapter开头的标题;

/^Chapter [1-9][0-9]{0,1}$/匹配开始和结尾都为章节标题,也就是说这一行只有章节标题;

/\bCha/匹配字边界,也就是说以Cha开头的边界;

/ter\b/结尾是ter的单词。

/\Bapt/,匹配非字边界,比如chapter中的apt匹配,但是aptitude中的就不匹配;

选择:用圆括号将所有项括起来,相邻的选择之间用|分隔。但是使用圆括号有一个副作用,是相关的匹配会被缓存,此时可用?:放在第一个选项前来消除这种副作用;

非捕获元:

?: 消除不想要的缓存副作用,放在选择项的第一个选项之前。
?= 正向预查,在任何开始匹配圆括号内的正则模式的位置来匹配搜索字符串。
?! 反向预查,在任何开始不匹配该正则模式的位置来匹配搜索字符串。

反向引用:(莫名想到了C语言里面的递归。。。)我觉得通俗的讲,反向引用,就是引用已经被缓存的模式也就是后文中的通过\n来对缓冲区进行访问。对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中(类似于子串,记得开始时有说过,正则就像数学表达式,由小的简单的表达式组合成为大的复杂的表达式,这些临时缓冲区可以理解为那些小表达式的匹配结果),所捕获的每个子匹配都按照在表达式中从左到右的顺序存储。缓冲区编号从1开始,最多可存储99个捕获的子表达式。每个缓冲区都可用\n来访问,其中n为一个标识特定缓冲区的一位或二位十进制数。可以使用非捕获元字符?:,?=,?!来重写捕获,忽略对相关匹配的缓存。

反向引用最简单最有用的应用之一,是提供查找文本中两个相同的相邻单词的匹配项的能力:

eg1:提取相同的单词。

var str=Is this the cost of of gasoline going up up?

var patt1= /\b([a-z]+) \1\b/;

document.write(str.match(patt1));

eg2:分割URL,从这个例子好像看出反向引用其实就是引用或者说提取大表达式中的子项,并使用,感觉这个反向引用有点晦涩难懂。(暂且放在这里,做个备忘,后期再修改);

var patt1 = /(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/;

arr = str.match(patt1);

二,正则表达式读的练习。

1./chapter [1-9][0-9]/

这个表达式匹配chapter +任何整数,比如1、19、109、10099.。。。。

首先前面的chapter是固定,【1-9】也是固定,然后【0-9】被限定符*限定,表示它可以出现零次或者多次。因此,可以是空,可以是一位,可以是多位。

2./[a-zA-z]+://[^\s]*/

匹配URL

3./\d{3}-\d{8}|\d{4}-\{7,8}/

匹配国内电话号码

4.\[1-9][0-9]{4,}\

匹配腾讯QQ号码

5.\[1-9]\d{5}(?!\d)\

匹配国内邮政编码

6.\^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$\

匹配十八位身份证号

7.\^[1-9]\d*$\

匹配正整数

8.\^-[1-9]\d*\

匹配负整数

9.\^-?[1-9]\d*$\

匹配整数

10.\^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$\

匹配正浮点数

11.\^-[1-9]\d*\.\d*|-0\.\d*[1-9]\d*$\

匹配负浮点数

三,JavaScript的RegExp对象

1.创建正则表达式对象

new RegExp(pattern, attributes);
pattern参数指代正则表达式,是一个字符串,attributes是一个可选参数包括g,i,m。分别指代全局匹配,区分大小写和多行匹配。

2.RegExP对象的属性:

global:RegExp对象是否具有标志m;

eg:if(patt1.global) { alert("Global property is set"); };

ignoreCase:RegExp对象是否具有标志m;

laseIndex:一个整数,标志开始下一次匹配的字符位置;

multiline:RegExp对象是否具有标志m;

source:正则表达式的原文本。

3.RegExp对象的方法

compile:编译正则表达式。

compile()有两种用途,第一种是在脚本执行过程中编译正则表达式。第二种是改变和重新编译正则表达式;

eg:RegExpObject.compile(regexp,modifier);

第一个参数为正则表达式,第二个参数规定匹配类型;

var str="Every man in the world! Every woman on earth!";

patt=/man/g;
str2=str.replace(patt,"person");
document.write(str2+"<br />");

patt=/(wo)?man/g;
patt.compile(patt);//这里改变了正则表达式
str2=str.replace(patt,"person");
document.write(str2);

exec:检索字符串中指定的值,返回找到的值并确定其位置。

eg:RegExpObject.exec(string);//返回一个结果,用于存放匹配的数组,如果未找到匹配,则为null。

说明:

exec() 方法的功能非常强大,它是一个通用的方法,而且使用起来也比 test() 方法以及支持正则表达式的 String 对象的方法更为复杂。

如果 exec() 找到了匹配的文本,则返回一个结果数组。否则,返回 null。此数组的第 0 个元素是与正则表达式相匹配的文本,第 1 个元素是与 RegExpObject 的第 1 个子表达式相匹配的文本(如果有的话),第 2 个元素是与 RegExpObject 的第 2 个子表达式相匹配的文本(如果有的话),以此类推。除了数组元素和 length 属性之外,exec() 方法还返回两个属性。index 属性声明的是匹配文本的第一个字符的位置。input 属性则存放的是被检索的字符串 string。在调用非全局的 RegExp 对象的 exec() 方法时,返回的数组与调用方法 String.match() 返回的数组是相同的。

但是,当 RegExpObject 是一个全局正则表达式时,exec() 的行为就稍微复杂一些。它会在 RegExpObject 的 lastIndex 属性指定的字符处开始检索字符串 string。当 exec() 找到了与表达式相匹配的文本时,在匹配后,它将把 RegExpObject 的 lastIndex 属性设置为匹配文本的最后一个字符的下一个位置。这就是说,可以通过反复调用 exec() 方法来遍历字符串中的所有匹配文本。当 exec() 再也找不到匹配的文本时,它将返回 null,并把 lastIndex 属性重置为 0。

提示和注释

重要事项:如果在一个字符串中完成了一次模式匹配之后要开始检索新的字符串,就必须手动地把 lastIndex 属性重置为 0。

提示:请注意,无论 RegExpObject 是否是全局模式,exec() 都会把完整的细节添加到它返回的数组中。这就是 exec() 与 String.match() 的不同之处,后者在全局模式下返回的信息要少得多。因此我们可以这么说,在循环中反复地调用 exec() 方法是唯一一种获得全局模式的完整模式匹配信息的方法。

var str = "正则表达式的exec方法测试"; 
var patt = new RegExp("exec","g");
var result;
while ((result = patt.exec(str)) != null)  {
          document.write('result:'+result);
            document.write("<br />");
            document.write('patt.lastIndex:'+patt.lastIndex);
          }

test:检索字符串中指定的值,返回true或false。

eg:var result = patt1.test(str);

4.支持正则表达式的string对象的方法

search:检索与正则表达式相匹配的值。

stringObj.search(regexp);//参数可以是子串,也可以是regexp对象。

注意:search()方法不执行全局匹配,它将忽略标志g,它同时忽略regexp的lastIndex属性,并且总是从字符串开始进行检索,所以他的返回值始终是sgringObj的第一个匹配的位置。如果要忽略大小写应追加i标记。

document.write(str.search(/abc/i);

match:找到一个或多个正则表达式的匹配。

stringObj.match(searchValue);//参数为要检索的字符串值

stringObj.match(regexp);//要匹配的模式的regexp对象。

返回存放匹配结果的数组。该数组的内容依赖于regexp是否具有全局属性g;

说明

match() 方法将检索字符串 stringObject,以找到一个或多个与 regexp 匹配的文本。这个方法的行为在很大程度上有赖于 regexp 是否具有标志 g。

如果 regexp 没有标志 g,那么 match() 方法就只能在 stringObject 中执行一次匹配。如果没有找到任何匹配的文本, match() 将返回 null。否则,它将返回一个数组,其中存放了与它找到的匹配文本有关的信息。该数组的第 0 个元素存放的是匹配文本,而其余的元素存放的是与正则表达式的子表达式匹配的文本。除了这些常规的数组元素之外,返回的数组还含有两个对象属性。index 属性声明的是匹配文本的起始字符在 stringObject 中的位置,input 属性声明的是对 stringObject 的引用。

如果 regexp 具有标志 g,则 match() 方法将执行全局检索,找到 stringObject 中的所有匹配子字符串。若没有找到任何匹配的子串,则返回 null。如果找到了一个或多个匹配子串,则返回一个数组。不过全局匹配返回的数组的内容与前者大不相同,它的数组元素中存放的是 stringObject 中所有的匹配子串,而且也没有 index 属性或 input 属性。

注意:在全局检索模式下,match() 即不提供与子表达式匹配的文本的信息,也不声明每个匹配子串的位置。如果您需要这些全局检索的信息,可以使用 RegExp.exec()。

eg:document.write(str.match(/\d+/g));

replace:替换与正则表达式匹配的子串。

stringObect.replace(regexp/substr,replacement);

regexp/substr:必须,正则表达式或者自字符串。

replacement):一个字符串值,规定了替换文本或生成替换文本的函数。

返回一个新的字符串,使用replacement替换第一次匹配或者所有匹配之后得到的。注意:指定g全局变量则替换所有的匹配,否则只替换第一次匹配到的字符串。

split:把字符串分割为字符串数组。

stringObect.split(separator,howmany);

separator:必须,字符串或正则表达式,从该参数指定的地方分割字符串;

howmany:可选,指定返回数组的最大长度,若设置了该参数,返回的子串不会多余这个参数指定的数组,如果没有设置该参数,整个字符串都会被分割。

返回一个字符串数组,不包括separator本身。