转自:http://www.cnblogs.com/rubylouvre/archive/2010/03/09/1681222.html
网上正则表达式的教程够多了,但由于javascript的历史比较悠久,也比较古老,因此有许多特性是不支持的。我们先从最简单地说起,文章所演示的正则基本都是perl方式。
元字符
( [ { \ ^ $ | ) ? * + .
预定义的特殊字符
字符 | 正则 | 描述 |
---|---|---|
\t | /\t/ | 制表符 |
\n | /\n/ | 制表符 |
\r | /\r/ | 回车符 |
\f | /\f/ | 换页符 |
\a | /\a/ | alert字符 |
\e | /\e/ | escape字符 |
\cX | /\cX/ | 与X相对应的控制字符 |
\b | /\b/ | 与回退字符 |
\v | /\v/ | 垂直制表符 |
\0 | /\0/ | 空字符 |
字符类
简单类
原则上正则的一个字符对应一个字符,我们可以用[]把它们括起来,让[]这个整体对应一个字符。如
alert(/ruby/.test("ruby"));//true
alert(/[abc]/.test("a"));//true
alert(/[abc]/.test("b"));//true
alert(/[abc]/.test("c"));//true
alert("a bat ,a Cat,a fAt bat ,a faT cat".match(/[bcf]at/gi));//bat,Cat,fAt,bat,faT,cat
负向类
也是在那个括号里做文章,前面加个元字符进行取反,表示匹配不能为括号里面的字符。
alert(/[^abc]/.test("a"));//false
alert(/[^abc]/.test("b"));//false
alert(/[^abc]/.test("6"));//true
alert(/[^abc]/.test("gg"));//true
范围类
还是在那个中括号里面做文章。有时匹配的东西过多,而且类型又相同,全部输入太麻烦,我们可以用它。特征就是在中间加了个横线。
组合类
还是在那个中括号里面做文章。允许用中括号匹配不同类型的单个字符。
alert(/[a-f]/.test("b"));//true
alert(/[a-f]/.test("k"));//false
alert(/[a-z]/.test("h"));//true
alert(/[A-Z]/.test("gg"));//false
alert(/[^H-Y]/.test("G"));//true
alert(/[0-9]/.test("8"));//true
alert(/[^7-9]/.test("6"));//true
alert(/[a-m1-5\n]/.test("a"))//true
alert(/[a-m1-5\n]/.test("3"))//true
var a = "\n\
"
alert(/[a-m1-5\n]/.test(a))//true
alert(/[a-m1-5\n]/.test("r"))//false
预定义类
还是在那个中括号里面做文章,不过它好像已经走到尽头了。由于是中括号的马甲,因此它们还是对应一个字符。
字符 | 等同于 | 描述 |
---|---|---|
. | [^\n\r] | 除了换行和回车之外的任意字符 |
\d | [0-9] | 数字字符 |
\D | [^0-9] | 非数字字符 |
\s | [ \t\n\x0B\f\r] | 空白字符 |
\S | [^ \t\n\x0B\f\r] | 非空白字符 |
\w | [a-zA-Z_0-9] | 单词字符(所有的字母) |
\W | [^a-zA-Z_0-9] | 非单词字符 |
alert(/\d/.test("3"))//true
alert(/\d/.test("w"))//false
alert(/\D/.test("w"))//true
alert(/\w/.test("w"))//true
alert(/\w/.test("司"))//false
alert(/\W/.test("徒"))//true
alert(/\s/.test(" "))//true
alert(/\S/.test(" "))//false
alert(/\S/.test("正"))//true
alert(/./.test("美"))//true
alert(/./.test(" "))//true
var a = "\n\
"
alert(/./.test(a))//true
量词
由于元字符与特殊字符或字符类或者它们的组合(中括号)甚至它们的马甲(预定义类)都是一对一进行匹配。我们要匹配“司徒正美这个词”,最简单都要/..../,如果长到50多个字符岂不是要死人。因此我们逼切需要一个简单的操作,来处理这数量关系。
简单量词
代码 | 类型 | 描述 |
---|---|---|
? | 软性量词 | 出现零次或一次 |
* | 软性量词 | 出现零次或多次(任意次) |
+ | 软性量词 | 出现一次或多次(至道一次) |
{n} | 硬性量词 | 对应零次或者n次 |
{n,m} | 软性量词 | 至少出现n次但不超过m次 |
{n,} | 软性量词 | 至少出现n次(+的升级版) |
alert(/..../.test("司徒正美"))//true
alert(/司徒正美/.test("司徒正美"))//true
alert(/[\u4e00-\u9fa5]{4}/.test("司徒正美"))//true
alert(/[\u4e00-\u9fa5]{4}/.test("司徒正美55"))//true
alert(/^[\u4e00-\u9fa5]+$/.test("正则表达式"))//true
alert(/^[\u4e00-\u9fa5]+$/.test("正则表达式&*@@"))//false
alert(/\d{6}/.test("123456"))//true
alert(/[ruby]{2}/.test("rr"))//true
alert(/[ruby]{2}/.test("ru"))//true
alert(/[ruby]{2}/.test("ry"))//true
/[\u4e00-\u9fa5]/用于匹配单个汉字。
贪婪量词,惰性量词与支配性量词
贪婪量词,上面提到的所有简单量词。就像成语中说的巴蛇吞象那样,一口吞下整个字符串,发现吞不下(匹配不了),再从后面一点点吐出来(去掉最后一个字符,再看这时这个整个字符串是否匹配,不断这样重复直到长度为零)
隋性量词,在简单量词后加问号。由于太懒了,先吃了前面第一个字符,如果不饱再捏起多添加一个(发现不匹配,就读下第二个,与最初的组成一个有两个字符串的字符串再尝试匹配,如果再不匹配,再吃一个组成拥有三个字符的字符串……)。其工作方式与贪婪量词相反。
支配性量词,在简单量词后加加号。上面两种都有个不断尝试的过程,而支配性量词却只尝试一次,不合口味就算了。就像一个出身高贵居支配地位的公主。但你也可以说它是最懒量词。由于javascript不支持,所以它连出场的机会也没有了。
var re1 = /.*bbb/g;//贪婪
var re2 = /.*?bbb/g;//惰性
// var re3 = /.*+bbb/g;//支配性,javascript不支持,IE与所有最新的标准浏览器都报错
alert(re1.test("abbbaabbbaaabbbb1234")+"");//true
alert(re1.exec("abbbaabbbaaabbbb1234")+"");//null
alert("abbbaabbbaaabbbb1234".match(re1)+"");//abbbaabbbaaabbbb
alert(re2.test("abbbaabbbaaabbbb1234")+"");//true
alert(re2.exec("abbbaabbbaaabbbb1234")+"");//aabbb
alert("abbbaabbbaaabbbb1234".match(re2)+"");//abbb,aabbb,aaabbb
分组
到目前为止,我们只能一个字符到匹配,虽然量词的出现,能帮助我们处理一排密紧密相连的同类型字符。但这是不够的,下面该轮到小括号出场了,中括号表示范围内选择,大括号表示重复次数。小括号允许我们重复多个字符。
//分组+量词
alert(/(dog){2}/.test("dogdog"))//true
//分组+范围
alert("baddad".match(/([bd]ad?)*/))//baddad,dad
//分组+分组
alert("mon and dad".match(/(mon( and dad)?)/))//mon and dad,mon and dad, and dad
反向引用
反向引用标识由正则表达式中的匹配组捕获的子字符串。每个反向引用都由一个编号或名称来标识,并通过“\编号”表示法进行引用。
var color = "#990000";
/#(\d+)/.test(color);
alert(RegExp.$1);//990000
alert(/(dog)\1/.test("dogdog"))//true
var num = "1234 5678";
var newNum = num.replace(/(\d{4}) (\d{4})/,"$2 $1");
alert(newNum)
候选
继续在分组上做文章。在分组中插入管道符(“|”),把它划分为两个或多个候多项。
var reg = /(red|black|yellow)!!/;
alert(reg.test("red!!"))//true
alert(reg.test("black!!"))//true
alert(reg.test("yellow!!"))//true
非捕获性分组
并不是所有分组都能创建反向引用,有一种特别的分组称之为非捕获性分组,它是不会创建反向引用。反之,就是捕获性分组。要创建一个非捕获性分组,只要在分组的左括号的后面紧跟一个问号与冒号就行了。
var color = "#990000";
/#(?:\d+)/.test(color);
alert(RegExp.$1);//""
题目,移除所有标签,只留下innerText!
var html = "<p><a href='http://www.cnblogs.com/rubylouvre/'>Ruby Louvre</a>by <em>司徒正美</em></p>";
var text = html.replace(/<(?:.|\s)*?>/g, "");
alert(text)
注意:javascript不存在命名分组
前瞻
继续在分组内做文章。前瞻与后瞻其实都属于零宽断言,但javascript不支持后瞻。
零宽断言 | ||
---|---|---|
正则 | 名称 | 描述 |
(?=exp) | 正向前瞻 | 匹配exp前面的位置 |
(?!exp) | 负向前瞻 | 匹配后面不是exp的位置 |
(?<=exp) | 正向后瞻 | 匹配exp后面的位置不支持 |
(?<!exp) | 负向后瞻 | 匹配前面不是exp的位置不支持 |
正向前瞻用来检查接下来的出现的是不是某个特定的字符集。而负向前瞻则是检查接下来的不应该出现的特定字符串集。零宽断言是不会被捕获的。
var str1 = "bedroom";
var str2 = "bedding";
var reBed = /(bed(?=room))///在我们捕获bed这个字符串时,抢先去看接下来的字符串是不是room
alert(reBed.test(str1));//true
alert(RegExp.$1)//bed
alert(RegExp.$2 === "")//true
alert(reBed.test(str2))//false
var str1 = "bedroom";
var str2 = "bedding";
var reBed = /(bed(?!room))/ //要来它后面不能是room
alert(reBed.test(str1))//false
alert(reBed.test(str2))//true
题目,移除hr以外的所有标签,只留下innerText!
var html = "<p><a href='http://www.cnblogs.com/rubylouvre/'>Ruby Louvre</a></p><hr/><p>by <em>司徒正美</em></p>";
var text = html.replace(/<(?!hr)(?:.|\s)*?>/ig,"")
alert(text)//Ruby Louvre<hr/>by 司徒正美
边界
一个要与字符类合用的东西。
边界 | ||
---|---|---|
正则 | 名称 | 描述 |
^ | 开头 | 注意不能紧跟于左中括号的后面 |
$ | 结尾 | |
\b | 单词边界 | 指[a-zA-Z_0-9]之外的字符 |
\B | 非单词边界 |
题目,设计一个字符串原型方法,实现首字母大写!
var a = "ruby";
String.prototype.capitalize = function () {
return this.replace(/^\w/, function (s) {
return s.toUpperCase();
});
}
alert(a.capitalize())//Ruby
单词边界举例。要匹配的东西的前端或未端不能为英文字母阿拉伯字数字或下横线。
var str = "12w-eefd&efrew";
alert(str.match(/\b\w+\b/g))//12w,eefd,efrew
实例属性 | 描述 |
---|---|
global | 是当前表达式模式首次匹配内容的开始位置,从0开始计数。其初始值为-1,每次成功匹配时,index属性都会随之改变。 |
ignoreCase | 返回创建RegExp对象实例时指定的ignoreCase标志(i)的状态。如果创建RegExp对象实例时设置了i标志,该属性返回True,否则返回False,默认值为False。 |
lastIndex | 是当前表达式模式首次匹配内容中最后一个字符的下一个位置,从0开始计数,常被作为继续搜索时的起始位置,初始值为-1, 表示从起始位置开始搜索,每次成功匹配时,lastIndex属性值都会随之改变。(只有使用exec()或test()方法才会填入,否则为0) |
multiLine | 返回创建RegExp对象实例时指定的multiLine标志(m)的状态。如果创建RegExp对象实例时设置了m标志,该属性返回True,否则返回False,默认值为False。 |
source | 返回创建RegExp对象实例时指定的表达式文本字符串。 |
var str = "JS's Louvre";
var reg = /\w/g;
alert(reg.exec(str));//J
alert(reg.lastIndex);//1
alert(reg.exec(str));//S
alert(reg.lastIndex);//2
alert(reg.exec(str));//s
alert(reg.lastIndex);//4
alert(reg.exec(str));//L
alert(reg.lastIndex);//6
==================================================================================================
正则表达式可以:
•测试字符串的某个模式。例如,可以对一个输入字符串进行测试,看在该字符串是否存在一个电话号码模式或一个信用卡号码模式。这称为数据有效性验证
•替换文本。可以在文档中使用一个正则表达式来标识特定文字,然后可以全部将其删除,或者替换为别的文字
•根据模式匹配从字符串中提取一个子字符串。可以用来在文本或输入字段中查找特定文字
正则表达式语法
一个正则表达式就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
创建正则表达式
- var re = new RegExp();//RegExp是一个对象,和Aarray一样
- //但这样没有任何效果,需要将正则表达式的内容作为字符串传递进去
- re =new RegExp("a");//最简单的正则表达式,将匹配字母a
- re=new RegExp("a","i");//第二个参数,表示匹配时不分大小写
RegExp构造函数第一个参数为正则表达式的文本内容,而第一个参数则为可选项标志.标志可以组合使用
•g (全文查找)
•i (忽略大小写)
•m (多行查找)
- var re = new RegExp("a","gi");//匹配所有的a或A
正则表达式还有另一种正则表达式字面量的声明方式
- var re = /a/gi;
和正则表达式相关的方法和属性
正则表达式对象的方法
•test,返回一个 Boolean 值,它指出在被查找的字符串中是否存在模式。如果存在则返回 true,否则就返回 false。
•exec,用正则表达式模式在字符串中运行查找,并返回包<script type="text/javascript" src="http://www.iteye.com/javascripts/tinymce/themes/advanced/langs/zh.js"></script><script
type="text/javascript" src="http://www.iteye.com/javascripts/tinymce/plugins/javaeye/langs/zh.js"></script>含该查找结果的一个数组。
•compile,把正则表达式编译为内部格式,从而执行得更快。
正则表达式对象的属性
•source,返回正则表达式模式的文本的复本。只读。
•lastIndex,返回字符位置,它是被查找字符串中下一次成功匹配的开始位置。
•$1...$9,返回九个在模式匹配期间找到的、最近保存的部分。只读。
•input ($_),返回执行规范表述查找的字符串。只读。
•lastMatch ($&),返回任何正则表达式搜索过程中的最后匹配的字符。只读。
•lastParen ($+),如果有的话,返回任何正则表达式查找过程中最后括的子匹配。只读。
•leftContext ($`),返回被查找的字符串中从字符串开始位置到最后匹配之前的位置之间的字符。只读。
•rightContext ($'),返回被搜索的字符串中从最后一个匹配位置开始到字符串结尾之间的字符。只读。
String对象一些和正则表达式相关的方法
•match,找到一个或多个正则表达式的匹配。
•replace,替换与正则表达式匹配的子串。
•search,检索与正则表达式相匹配的值。
•split,把字符串分割为字符串数组。
测试正则表达式是如何工作的!
- //test方法,测试字符串,符合模式时返回true,否则返回false
- var re = /he/;//最简单的正则表达式,将匹配he这个单词
- var str = "he";
- alert(re.test(str));//true
- str = "we";
- alert(re.test(str));//false
- str = "HE";
- alert(re.test(str));//false,大写,如果要大小写都匹配可以指定i标志(i是ignoreCase或case-insensitive的表示)
- re = /he/i;
- alert(re.test(str));//true
- str = "Certainly!He loves her!";
- alert(re.test(str));//true,只要包含he(HE)就符合,如果要只是he或HE,不能有其它字符,则可使用^和$
- re = /^he/i;//脱字符(^)代表字符开始位置
- alert(re.test(str));//false,因为he不在str最开始
- str = "He is a good boy!";
- alert(re.test(str));//true,He是字符开始位置,还需要使用$
- re = /^he$/i;//$表示字符结束位置
- alert(re.test(str));//false
- str = "He";
- alert(re.test(str));//true
- //当然,这样不能发现正则表达式有多强大,因为我们完全可以在上面的例子中使用==或indexOf
- re = /\s/;// \s匹配任何空白字符,包括空格、制表符、换页符等等
- str= "user Name";//用户名包含空格
- alert(re.test(str));//true
- str = "user Name";//用户名包含制表符
- alert(re.test(str));//true
- re=/^[a-z]/i;//[]匹配指定范围内的任意字符,这里将匹配英文字母,不区分大小写
- str="variableName";//变量名必须以字母开头
- alert(re.test(str));//true
- str="123abc";
- alert(re.test(str));//false
当然,仅仅知道了字符串是否匹配模式还不够,我们还需要知道哪些字符匹配了模式
- var osVersion = "Ubuntu 8";//其中的8表示系统主版本号
- var re = /^[a-z]+\s+\d+$/i; //+号表示字符至少要出现1次,\s表示空白字符,\d表示一个数字
- alert(re.test(osVersion));//true,但我们想知道主版本号
- //另一个方法exec,返回一个数组,数组的第一个元素为完整的匹配内容
- re=/^[a-z]+\s+\d+$/i;
- arr = re.exec(osVersion);
- alert(arr[0]);//将osVersion完整输出,因为整个字符串刚好匹配re
- //我只需要取出数字
- re=/\d+/;
- var arr = re.exec(osVersion);
- alert(arr[0]);//8
更复杂的用法,使用子匹配
- //exec返回的数组第1到n元素中包含的是匹配中出现的任意一个子匹配
- re=/^[a-z]+\s+(\d+)$/i;//用()来创建子匹配
- arr =re.exec(osVersion);
- alert(arr[0]);//整个osVersion,也就是正则表达式的完整匹配
- alert(arr[1]);//8,第一个子匹配,事实也可以这样取出主版本号
- alert(arr.length);//2
- osVersion = "Ubuntu 8.10";//取出主版本号和次版本号
- re = /^[a-z]+\s+(\d+)\.(\d+)$/i;//.是正则表达式元字符之一,若要用它的字面意义须转义
- arr = re.exec(osVersion);
- alert(arr[0]);//完整的osVersion
- alert(arr[1]);//8
- alert(arr[2]);//10
注意,当字符串不匹配re时,exec方法将返回null
String对象的一些和正则表达式有关的方法
- //replace方法,用于替换字符串
- var str ="some money";
- alert(str.replace("some","much"));//much money
- //replace的第一个参数可以为正则表达式
- var re = /\s/;//空白字符
- alert(str.replace(re,"%"));//some%money
- //在不知道字符串中有多少空白字符时,正则表达式极为方便
- str ="some some \tsome\t\f";
- re = /\s+/;
- alert(str.replace(re,"#"));//但这样只会将第一次出现的一堆空白字符替换掉
- //因为一个正则表达式只能进行一次匹配,\s+匹配了第一个空格后就退出了
- re = /\s+/g;//g,全局标志,将使正则表达式匹配整个字符串
- alert(str.replace(re,"@"));//some@some@some@
- //另一个与之相似的是split
- var str = "a-bd-c";
- var arr = str.split("-");//返回["a","bd","c"]
- //如果str是用户输入的,他可能输入a-bd-c也可能输入a bd c或a_bd_c,但不会是abdc(这样就说他输错了)
- str = "a_db-c";//用户以他喜欢的方式加分隔符s
- re=/[^a-z]/i;//前面我们说^表示字符开始,但在[]里它表示一个负字符集
- //匹配任何不在指定范围内的任意字符,这里将匹配除字母处的所有字符
- arr = str.split(re);//仍返回["a","bd","c"];
- //在字符串中查找时我们常用indexOf,与之对应用于正则查找的方法是search
- str = "My age is 18.Golden age!";//年龄不是一定的,我们用indexOf不能查找它的位置
- re = /\d+/;
- alert(str.search(re));//返回查找到的字符串开始下标10
- //注意,因为查找本身就是出现第一次就立即返回,所以无需在search时使用g标志
- //下面的代码虽然不出错,但g标志是多余的
- re=/\d+/g;
- alert(str.search(re));//仍然是10
注意,当search方法没有找到匹配时,将返回-1
类似于exec方法,String对象的match方法也用于将字符串与正则表达式进行匹配并返回结果数组
- var str = "My name is CJ.Hello everyone!";
- var re = /[A-Z]/;//匹配所有大写字母
- var arr = str.match(re);//返回数组
- alert(arr);//数组中只会包含一个M,因为我们没有使用全局匹配
- re = /[A-Z]/g;
- arr = str.match(re);
- alert(arr);//M,C,J,H
- //从字符串中抽取单词
- re = /\b[a-z]*\b/gi;//\b表示单词边界
- str = "one two three four";
- alert(str.match(re));//one,two,three,four
RegExp对象实例的一些属性
- var re = /[a-z]/i;
- alert(re.source);//将[a-z]字符串输出
- //请注意,直接alert(re)会将正则表达式连同前向斜线与标志输出,这是re.toString方法定义的
每个RegExp对象的实例具有lastIndex属性,它是被查找字符串中下一次成功匹配的开始位置,默认值是-1。 lastIndex 属性被 RegExp 对象的 exec 和 test 方法修改.并且它是可写的.
- var re = /[A-Z]/;
- //exec方法执行后,修改了re的lastIndex属性,
- var str = "Hello,World!!!";
- var arr = re.exec(str);
- alert(re.lastIndex);//0,因为没有设置全局标志
- re = /[A-Z]/g;
- arr = re.exec(str);
- alert(re.lastIndex);//1
- arr = re.exec(str);
- alert(re.lastIndex);//7
当匹配失败(后面没有匹配),或lastIndex值大于字符串长度时,再执行exec等方法会将lastIndex设为0(开始位置)
- var re = /[A-Z]/;
- var str = "Hello,World!!!";
- re.lastIndex = 120;
- var arr = re.exec(str);
- alert(re.lastIndex);//0
RegExp对象的静态属性
- //input 最后用于匹配的字符串(传递给test,exec方法的字符串)
- var re = /[A-Z]/;
- var str = "Hello,World!!!";
- var arr = re.exec(str);
- alert(RegExp.input);//Hello,World!!!
- re.exec("tempstr");
- alert(RegExp.input);//仍然是Hello,World!!!,因为tempstr不匹配
- //lastMatch 最后匹配的字符
- re = /[a-z]/g;
- str = "hi";
- re.test(str);
- alert(RegExp.lastMatch);//h
- re.test(str);
- alert(RegExp["$&"]);//i ,$&是lastMatch的短名字,但由于它不是合法变量名,所以要。。
- //lastParen 最后匹配的分组
- re = /[a-z](\d+)/gi;
- str = "Class1 Class2 Class3";
- re.test(str);
- alert(RegExp.lastParen);//1
- re.test(str);
- alert(RegExp["$+"]);//2
- //leftContext 返回被查找的字符串中从字符串开始位置到最后匹配之前的位置之间的字符
- //rigthContext 返回被搜索的字符串中从最后一个匹配位置开始到字符串结尾之间的字符
- re = /[A-Z]/g;
- str = "123ABC456";
- re.test(str);
- alert(RegExp.leftContext);//123
- alert(RegExp.rightContext);//BC456
- re.test(str);
- alert(RegExp["$`"]);//123A
- alert(RegExp["$'"]);//C456
multiline属性返回正则表达式是否使用多行模式,这个属性不针对某个正则表达式实例,而是针对所有正则表达式,并且这个属性可写.(IE与Opera不支持这个属性)
- alert(RegExp.multiline);
- //因为IE,Opera不支持这个属性,所以最好还是单独指定
- var re = /\w+/m;
- alert(re.multiline);
- alert(RegExp["$*"]);//RegExp对象的静态属性不会因为给RegExp某个对象实例指定了m标志而改变
- RegExp.multiline = true;//这将打开所有正则表达式实例的多行匹配模式
- alert(RegExp.multiline);
使用元字符注意事项:元字符是正则表达式的一部分,当我们要匹配正则表达式本身时,必须对这些元字符转义.下面是正则表达式用到的所有元字符
( [ { \ ^ $ | ) ? * + .
- var str = "?";
- var re = /?/;
- alert(re.test(str));//出错,因为?是元字符,必须转义
- re = /\?/;
- alert(re.test(str));//true
使用RegExp构造函数与使用正则表达式字面量创建正则表达式注意点
- var str = "\?";
- alert(str);//只会输出?
- var re = /\?/;//将匹配?
- alert(re.test(str));//true
- re = new RegExp("\?");//出错,因为这相当于re = /\?/
- re = new RegExp("\\?");//正确,将匹配?
- alert(re.test(str));//true
既然双重转义这么不友好,所以还是用正则表达式字面量的声明方式
如何在正则表达式中使用特殊字符?
- //ASCII方式用十六进制数来表示特殊字符
- var re = /^\x43\x4A$/;//将匹配CJ
- alert(re.test("CJ"));//true
- //也可使用八进制方式
- re = /^\103\112$/;//将匹配CJ
- alert(re.test("CJ"));//true
- //还可以使用Unicode编码
- re =/^\u0043\u004A$/;//使用 Unicode,必须使用u开头,接着是字符编码的四位16进制表现形式
- alert(re.test("CJ"));
另处,还有一些其它的预定义特殊字符,如下表所示:
字符 描述
\n 换行符
\r 回车符
\t 制表符
\f 换页符(Tab)
\cX 与X对应的控制字符
\b 退格符(BackSpace)
\v 垂直制表符
\0 空字符("")
字符类 ---〉简单类,反向类,范围类,组合类,预定义类
- //简单类
- var re = /[abc123]/;//将匹配abc123这6个字符中一个
- //负向类
- re = /[^abc]/;//将匹配除abc之外的一个字符
- //范围类
- re = /[a-b]/;//将匹配小写a-b 26个字母
- re = /[^0-9]/;//将匹配除0-9 10个字符之处的一个字符
- //组合类
- re = /[a-b0-9A-Z_]/;//将匹配字母,数字和下划线
下面是正则表达式中的预定义类
代码 等同于 匹配
. IE下[^\n],其它[^\n\r] 匹配除换行符之外的任何一个字符
\d [0-9] 匹配数字
\D [^0-9] 匹配非数字字符
\s [ \n\r\t\f\x0B] 匹配一个空白字符
\S [^ \n\r\t\f\x0B] 匹配一个非空白字符
\w [a-zA-Z0-9_] 匹配字母数字和下划线
\W [^a-zA-Z0-9_] 匹配除字母数字下划线之外的字符
量词(下表量词单个出现时皆是贪婪量词)
代码 描述
* 匹配前面的子表达式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。 * 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,}。
? 匹配前面的子表达式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等价于 {0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。刘, "o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。
贪婪量词与惰性量词
•用贪婪量词进行匹配时,它首先会将整会字符串当成一个匹配,如果匹配的话就退出,如果不匹配,就截去最后一个字符进行匹配,如果不匹配,继续将最后一个字符截去进行匹配,直到有匹配为止。直到现在我们遇到的量词都是贪婪量词
•用惰性量词进行匹配时,它首先将第一个字符当成一个匹配,如果成功则退出,如果失败,则测试前两个字符,依些增加,直到遇到合适的匹配为止
惰性量词仅仅在贪婪量词后面加个"?"而已,如"a+"是贪婪匹配的,"a+?"则是惰性的
- var str = "abc";
- var re = /\w+/;//将匹配abc
- re = /\w+?/;//将匹配a
多行模式
- var re = /[a-z]$/;
- var str = "ab\ncdef";
- alert(str.replace(re,"#"));//ab\ncde#
- re =/[a-z]$/m;
- alert(str.replace(re,"#"));//a#\ncde#
分组与非捕获性分组
- re = /abc{2}/;//将匹配abcc
- re = /(abc){2}/;//将匹配abcabc
- //上面的分组都是捕获性分组
- str = "abcabc ###";
- arr = re.exec(str);
- alert(arr[1]);//abc
- //非捕获性分组 (?:)
- re = /(?:abc){2}/;
- arr = re.exec(str);
- alert(arr[1]);//undefined
候选(也就是所说的“或”)
- re = /^a|bc$/;//将匹配开始位置的a或结束位置的bc
- str ="add";
- alert(re.test(str));//true
- re = /^(a|bc)$/;//将匹配a或bc
- str ="bc";
- alert(re.test(str));//true
当包含分组的正则表达式进行过test,match,search这些方法之后,每个分组都被放在一个特殊的地方以备将来使用,这些存储是分组中的特殊值,我们称之为反向引用
- var re = /(A?(B?(C?)))/;
- /*上面的正则表达式将依次产生三个分组
- (A?(B?(C?))) 最外面的
- (B?(C?))
- (C?)*/
- str = "ABC";
- re.test(str);//反向引用被存储在RegExp对象的静态属性$1—$9中
- alert(RegExp.$1+"\n"+RegExp.$2+"\n"+RegExp.$3);
- //反向引用也可以在正则表达式中使用\1 ,\2...这类的形式使用
- re = /\d+(\D)\d+\1\d+/;
- str = "2008-1-1";
- alert(re.test(str));//true
- str = "2008-4_3";
- alert(re.test(str));//false
使用反向引用可以要求字符串中某几个位置上的字符必须相同.另外,在replace这类方法中可用特殊字符序列来表示反向引用
- re = /(\d)\s(\d)/;
- str = "1234 5678";
- alert(str.replace(re,"$2 $1"));//在这个里面$1表示第一个分组1234,$2则表示5678
其它——〉正向前瞻,用来捕获出现在特定字符之前的字符,只有当字符后面跟着某个特定字符才去捕获它。与正向前瞻对应的有负向前瞻,它用匹配只有当字符后面不跟着某个特定字符时才去匹配它。在执行前瞻和负向前瞻之类的运算时,正则表达式引擎会留意字符串后面的部分,然而却不移动index
- //正向前瞻
- re = /([a-z]+(?=\d))/i;
- //我们要匹配后面跟一个数字的单词,然后将单词返回,而不要返回数字
- str = "abc every1 abc";
- alert(re.test(str));//true
- alert(RegExp.$1);//every
- alert(re.lastIndex);//使用前瞻的好处是,前瞻的内容(?=\d)并不会当成一次匹配,下次匹配仍从它开始
- //负向前瞻(?!)
- re = /([a-z](?!\d))/;i
- //将匹配后面不包含数字的字母,并且不会返回(?!\d)中的内容
- str = "abc1 one";
- alert(re.test(str));
- alert(RegExp.$1);//one
构建一个验证电子邮箱地址有效性的正则表达式。电子邮箱地址有效性要求(我们姑且这样定义):用户名只能包含字母数字以及下划线,最少一位,最多25位,用户名后面紧跟@,后面是域名,域名名称要求只能包含字母数字和减号(-),并且不能以减号开头或结尾,然后后面是域名后缀(可以有多个),域名后缀必须是点号连上2-4位英文字母
- var re = /^\w{1,15}(?:@(?!-))(?:(?:[a-z0-9-]*)(?:[a-z0-9](?!-))(?:\.(?!-)))+[a-z]{2,4}$/;
==================================================================================================
什么是正则表达式?
这个问题可以参见:“正则表达式30分钟入门教程”,很多编程语言都支持正则表达式,本文仅仅讨论JavaScript中的正则表达式。
创建一个正则表达式
第一种方法:
第二种方法:
正则表达式的exec方法简介
语法:
其中str为要执行正则表达式的目标字符串。
例如:
将会输出test,因为正则表达式reg会匹配str(‘testString’)中的’test’子字符串,并且将其返回。
我们使用下面的函数来做匹配正则的练习:
函数接受一个正则表达式参数reg和一个目标字符串参数str,执行之后会alert出正则表达式与字符串的匹配结果。
用这个函数测试上面的例子就是:
上面的例子用正则里的test去匹配字符串里的test,实在是很无聊,同样的任务用indexOf方法就可以完成了。用正则,自然是要完成更强大的功能:
一片两片三四片,落尽正则全不见
上面的小标题翻译成正则就是{1},{2},{3,4},{1,}。
c{n}
{1}表示一个的意思。
/c{1}/只能匹配一个c。
/c{2}/则会匹配两个连续的c。
以此类推,
/c{n}/则会匹配n个连续的c。
看下面的例子:
返回结果c
返回结果null,表示没有匹配成功。
返回结果cc。
c{m,n}
c{3,4}的意思是,连续的3个c或者4个c。
例如
返回结果null,表示没有匹配成功。
结果返回ccc。
结果返回cccc,这表明正则会尽量多匹配,可3可4的时候它会选择多匹配一个。
仍然只匹配4个c。
由以上例子可以推断出,c{m,n}表示m个到n个c,且m小于等于n。
c{n,}
c{1,}表示1个以上的c。例如:
结果返回c。
返回ccccc,再次说明了正则表达式会尽量多地匹配。
结果返回null,c{2,}表示2个以上的c,而cainiao中只有1个c。
由以上例子可知,c{n,}表示最少n个c,最多则不限个数。
*,+,?
*表示0次或者多次,等同于{0,},即
c* 和 c{0,} 是一个意思。
+表示一次或者多次,等同于{1,},即
c+ 和 c{1,} 是一个意思。
最后,?表示0次或者1次,等同于{0,1},即
c? 和 c{0,1} 是一个意思。
贪心与非贪心
人都是贪婪的,正则也是如此。我们在例子reg = /c{3,4}/;str='ccccTest';的例子中已经看到了,能匹配四个的时候,正则绝对不会去匹配三个。上面所介绍的所有的正则都是这样,只要在合法的情况下,它们会尽量多去匹配字符,这就叫做贪心模式。
如果我们希望正则尽量少地匹配字符,那么就可以在表示数字的符号后面加上一个?。组成如下的形式:
{n,}?, *?, +?, ??, {m,n}?
同样来看一个例子:
返回的结果只有1个c,尽管有5个c可以匹配,但是由于正则表达式是非贪心模式,所以只会匹配一个。
/^开头,结尾$/
^表示只匹配字符串的开头。看下面的例子:
结果为null,因为字符串‘维生素c’的开头并不是c,所以匹配失败。
这次则返回c,匹配成功,因为cainiao恰恰是以c开头的。
与^相反,$则只匹配字符串结尾的字符,同样,看例子:
返回null,表示正则表达式没能在字符串的结尾找到c这个字符。
这次返回的结果是c,表明匹配成功。
点’.’
‘.’会匹配字符串中除了换行符\n之外的所有字符,例如
结果显示,正则匹配到了字符c。
这次是b。
结果是“blueidea——经典论坛 好_。“也就是说所有的字符都被匹配掉了,包括一个空格,一个下滑线,和一个破折号。
同样,直接返回整个字符串——bbs.blueidea.com,可见”.”也匹配”.”本身。
结果是null,终于失败了,正则要求字符串的第一个字符不是换行,但是恰恰字符是以\n开始的。
二选一,正则表达式中的或,“|“
b|c表示,匹配b或者c。
例如:
结果是b。
结果是c。
匹配掉整个cainiao。
结果只有一个b,而不是整个字符串。因为上面正则表达式的意思是,匹配开头的b或者是c.+。
括号
这次的结果是整个串bbs.blueidea.com,加上上面的括号后,这个正则的意思是,如果字符串的开头是b或者c,那么匹配开头的b或者c以及其后的所有的非换行字符。
如果你也实验了的话,会发现返回的结果后面多出来一个“,b“,这是()内的b|c所匹配的内容。我们在正则表达式内括号里写的内容会被认为是子正则表达式,所匹配的结果也会被记录下来供后面使用。我们暂且不去理会这个特性。
字符集合[abc]
[abc]表示a或者b或者c中的任意一个字符。例如:
返回结果是b。
这次的结果就是null了。
我们在字字符集合中使用如下的表示方式:[a-z],[A-Z],[0-9],分别表示小写字母,大写字母,数字。例如:
结果是整个test,正则的意思是开头必须是英文字母,后面可以是英文字母或者数字以及下划线。
反字符集合[^abc]
^在正则表达式开始部分的时候表示开头的意思,例如/^c/表示开头是c;但是在字符集和中,它表示的是类似“非“的意思,例如[^abc]就表示不能是a,b或者c中的任何一个。例如:
返回的结果是l,因为它是第一个非abc的字符(即第一个b没有匹配)。同样:
则返回i,前两个字符都是[abc]集合中的。
由此我们可知:[^0-9]表示非数字,[^a-z]表示非小写字母,一次类推。
边界与非边界
\b表示的边界的意思,也就是说,只有字符串的开头和结尾才算数。例如/\bc/就表示字符串开始的c或者是结尾的c。看下面的例子:
返回结果c。匹配到了左边界的c字符。
仍然返回c,不过这次返回的是右侧边界的c。
这次匹配失败,因为bcb字符串中的c被夹在中间,既不在左边界也不再右边界。
与\b对应\B表示非边界。例如:
这次会成功地匹配到bcb中的c,。然而
则会返回null。因为\B告诉正则,只匹配非边界的c。
数字与非数字
\d表示数字的意思,相反,\D表示非数字。例如:
返回的匹配结果为8,因为它是第一个数字字符。
返回c,第一个非数字字符。
空白
\f匹配换页符,\n匹配换行符,\r匹配回车,\t匹配制表符,\v匹配垂直制表符。
\s匹配单个空格,等同于[\f\n\r\t\v]。例如:
返回“is a test String.”,正则的意思是匹配第一个空格以及其后的所有非换行字符。
同样,\S表示非空格字符。
匹配结果为This,当遇到第一个空格之后,正则就停止匹配了。
单词字符
\w表示单词字符,等同于字符集合[a-zA-Z0-9_]。例如:
返回完整的blueidea字符串,因为所有字符都是单词字符。
结果显示匹配了字符串中的className,只有第一个“.”——唯一的非单词字符没有匹配。
试图用单词字符去匹配中文自然行不通了,返回null。
\W表示非单词字符,等效于[^a-zA-Z0-9_]
返回完整的字符串,因为,无论是中文和“?”都算作是非单词字符。
反向引用
形式如下:/(子正则表达式)\1/
依旧用例子来说明:
1.
返回b。
2.
返回bl,b,l
bl是整个正则匹配的内容,b是第一个括号里的子正则表达式匹配的内容,l是第二个括号匹配的内容。
3.
则会返回null。这里的“\1”就叫做反向引用,它表示的是第一个括号内的字正则表达式匹配的内容。在上面的例子中,第一个括号里的(\w)匹配了b,因此“\1”就同样表示b了,在余下的字符串里自然找不到b了。
与第二个例子对比就可以发现,“\1”是等同于“第1个括号匹配的内容”,而不是“第一个括号的内容”。
这个正则则会匹配到bb。
同样,前面有几个子正则表达式我们就可以使用几个反向引用。例如:
会匹配成功,因为第一个括号匹配到w,第二个括号匹配到o,而\2\1则表示ow,恰好匹配了字符串的最后两个字符。
括号(2)
前面我们曾经讨论过一次括号的问题,见下面这个例子:
这个正则是为了实现只匹配以b或者c开头的字符串,一直匹配到换行字符,但是。上面我们已经看到了,可以使用“\1”来反向引用这个括号里的子正则表达式所匹配的内容。而且exec方法也会将这个字正则表达式的匹配结果保存到返回的结果中。
不记录子正则表达式的匹配结果
使用形如(?:pattern)的正则就可以避免保存括号内的匹配结果。例如:
可以看到返回的结果不再包括那个括号内的字正则表达式多匹配的内容。
同理,反向引用也不好使了:
返回bb,b。bb是整个正则表达式匹配的内容,而b是第一个子正则表达式匹配的内容。
返回null。由于根本就没有记录括号内匹配的内容,自然没有办法反向引用了。
正向预查
形式:(?=pattern)
所谓正向预查,意思就是:要匹配的字符串,后面必须紧跟着pattern!
我们知道正则表达式/cainiao/会匹配cainiao。同样,也会匹配cainiao9中的cainiao。但是我们可能希望,cainiao只能匹配cainiao8中的菜鸟。这时候就可以像下面这样写:/cainiao(?=8)/,看两个实例:
返回null。
匹配cainiao。
需要注意的是,括号里的内容并不参与真正的匹配,只是检查一下后面的字符是否符合要求而已,例如上面的正则,返回的是cainiao,而不是cainiao8。
再来看两个例子:
匹配到blue,而不是blueidea。
返回null,因为blue后面不是idea。
同样返回null。
?!
形式(?!pattern)和?=恰好相反,要求字符串的后面不能紧跟着某个pattern,还拿上面的例子:
返回null,因为正则要求,blue的后面不能是idea。
则成功返回blue。
匹配元字符
首先要搞清楚什么是元字符呢?我们之前用过*,+,?之类的符号,它们在正则表达式中都有一定的特殊含义,类似这些有特殊功能的字符都叫做元字符。例如
表示有任意个c,但是如果我们真的想匹配’c*’这个字符串的时候怎么办呢?只要将*转义了就可以了,如下:
返回匹配的字符串:c*。
同理,要匹配其他元字符,只要在前面加上一个“\”就可以了。
正则表达式的修饰符
全局匹配,修饰符g
形式:/pattern/g
例子:reg = /b/g;
后面再说这个g的作用。先看后面的两个修饰符。
不区分大小写,修饰符i
形式:/pattern/i
例子:
返回null,因为大小写不符合。
匹配到B,这个就是i修饰符的作用了。
行首行尾,修饰符m
形式:/pattern/m
m修饰符的作用是修改^和$在正则表达式中的作用,让它们分别表示行首和行尾。例如:
匹配失败,因为字符串的开头没有b字符。但是加上m修饰符之后:
匹配到b,因为加了m修饰符之后,^已经表示行首,由于bbs在字符串第二行的行首,所以可以成功地匹配。
exec方法详解
exec方法的返回值
exec方法返回的其实并不是匹配结果字符串,而是一个对象,简单地修改一下execReg函数,来做一个实验就可以印证这一点:
function execReg(reg,str){ var result = reg.exec(str); alert(typeof
result); } var reg = /b/; var str='bbs.bblueidea.com'; execReg(reg,str);
结果显示result的类型是object。而且是一个类似数组的对象。使用for in可以知道它的属性: index input 0。其中index是表示匹配在原字符串中的索引;而input则是表示输入的字符串;
至于0则是表示只有一个匹配结果,可以用下标0来引用这个匹配结果,这个数量可能改变。我们可以通过返回值的length属性来得知匹配结果的总数量。
根据以上对返回值的分析,修改execReg函数如下:
马上来实验一下:
结果如下:
index:0
input:bbs.bblueidea.com
result[0]:b
输入字符串为bbs.bblueidea.com;
匹配的b在原字符串的索引是0。
正则的匹配结果为一个,b;
结果为:
index:0
input:bbs.bblueidea.com
result[0]:bbs.bblueidea.com
result[1]:b
result[2]:b
result[3]:s.bblueidea.com
由上面两个例子可见,返回对象[0]就是整个正则表达式所匹配的内容。后续的元素则是各个子正则表达式的匹配内容。
exec方法对正则表达式的更新
exec方法在返回结果对象的同时,还可能会更新原来的正则表达式,这就要看正则表达式是否设置了g修饰符。先来看两个例子吧:
结果如下:
index:0
input:bbs.blueidea.com
result[0]:b
index:0
input:bbs.blueidea.com
result[0]:b
也就是说,两次匹配的结果完全一样,从索引可以看出来,匹配的都是字符串首的b字符。
下面看看设置了g的正则表达式表现如何:
结果如下:
index:0
input:bbs.blueidea.com
result[0]:b
index:1
input:bbs.blueidea.com
result[0]:b
可以看得出来,第二次匹配的是字符串的字符串的第二个b。这也就是g修饰符的作用了,下面来看exec是如何区别对待g和非g正则表达式的。
如果正则表达式没有设置g,那么exec方法不会对正则表达式有任何的影响,如果设置了g,那么exec执行之后会更新正则表达式的lastIndex属性,表示本次匹配后,所匹配字符串的下一个字符的索引,下一次再用这个正则表达式匹配字符串的时候就会从上次的lastIndex属性开始匹配,也就是上面两个例子结果不同的原因了。
test方法
test方法仅仅检查是否能够匹配str,并且返回布尔值以表示是否成功。同样建立一个简单的测试函数:
实例1
成功,输出true。
实例2
失败,返回false。
使用字符串的方法执行正则表达式
match方法
形式:str.match(reg);
与正则表达式的exec方法类似,该方法同样返回一个类似数组的对象,也有input和index属性。我们定义如下一个函数用来测试:
例如:
结果如下:
index:0
input:bbs.blueidea.com
result[0]:b
可见,和exec的结果一样。
但是如果正则表达式设置了g修饰符,exec和match的行为可就不一样了,见下例:
index:undefined
input:undefined
result[0]:b
result[1]:b
result[2]:b
设置了g修饰符的正则表达式在完成一次成功匹配后不会停止,而是继续找到所有可以匹配到的字符。返回的结果包括了三个b。不过没有提供input和index这些信息。
replace方法
形式:str. replace (reg,’new str’);
它的作用是将str字符串中匹配reg的部分用’’new str”部分代码,值得注意的是原字符串并不会被修改,而是作为返回值被返回。例子:
结果为cbs.blueidea.com,只有第一个b被替换为c。
输出ccs.clueidea.com
由于,设置了g修饰符,所以会替换掉所有的b。
输出:
word.word.word。
在replace函数中使用$引用子正则表达式匹配内容
就像在正则里我们可以使用\1来引用第一个子正则表达式所匹配的内容一样,我们在replace函数的替换字符里也可以使用$1来引用相同的内容。
还是来看一个例子吧:
输出的结果为:
bbs.bbs.bbs
首先,我们知道第一个子正则表达式匹配到了bbs,那么$1也就代表bbs了。其后我们把替换字符串设置为'$1.$1.$1',其实也就是“bbs.bbs.bbs”。同理,$2就是blueidea,$3就是com。
在来看一个例子,颠倒空格前后两个单词的顺序。
结果为:gaoshou cainiao,也就是空格前后的单词被调换顺序了。
由于在替换文本里$有了特殊的含义,所以我们如果想要是用$这个字符的话,需要写成$$,例如:
结果为:$ $。
search方法和split方法
同样,字符串的search方法和split方法中也可以使用正则表达式,形式如下:
str.search(reg);
search返回正则表达式第一次匹配的位置。例子:
结果为4
下面的例子找出第一个非单词字符:
结果为3,也就是那个点“.”的位置。
结果为:bbs,blueidea,com,可见数组被非单词字符分为了有三个元素的数组。
结果为:
7
http,,,www,baidu,com,
可见字符串被分为了有7个元素的数组,其中包括了三个为空字符串的元素。