正则表达式(regex or regexp) 通过检索特定模式的一个或多个匹配(即特定的ASCII或者unicode字符序列 ),从任何文本中提取信息,这是非常有用的。
应用范围:解析、替换字符串,数据格式转换,以及网页抓取。
有趣的是,一旦你学会了它的语法,几乎可以在所有编程语言中使用这个工具(JavaScript, Java, VB, C #, C / C , Python, Perl, Ruby, Delphi, R, Tcl, and many others),它们之中只有微小的区别。
让我们来看看一些例子和解析。
基本语法边界匹配??—?? ^ and $
^The 匹配任何以The开始的字符串
end$ 匹配任何以End结尾的字符串
^The end$ 准确地匹配字符串 (The开始,End结尾)
roar 匹配任何含有roar的字符串
量词??—?? * ? and {}
abc* 匹配ab后跟零或多次c的字符串 [0, ∞]
abc 匹配ab后一次或多次c的字符串 [1, ∞]
abc? 匹配ab后零次或一次c的字符串 [0, 1]
abc{2} 匹配ab后2次c的字符串
abc{2,} 匹配ab后2次或更多次c的字符串
abc{2,5} 匹配ab后2到5次c的字符串
a(bc)* 匹配a后零次或多次bc的字符串
a(bc){2,5} 匹配a后2到5次bc的字符串
或 — | or []
a(b|c) 匹配a后跟b或c的字符串
a[b|c] 与上述一致
字符类 —??\d \w \s and .
\d 匹配一个数字
\w 匹配一个字符(字母、数字、字符、下划线)
\s 匹配一个空格(包括tabs、换行\n)
. 匹配任何非空字符(不包含换行\n等空字符)
[\s\S] 匹配任何字符
谨慎使用.元字符,因为字符类和否定字符类处理更快、更准确。
\d, \w 和 \s 分别使用 \D, \W 和 \S 表示它们的否定。
比如,\D将匹配与\d相反的字符。
\D 匹配一个非数字的字符
为了正确的理解,你必须使用反斜杠\ 来转义字符^.[$()|* ?{\, 因为它们具有特殊的含义。
$\d 匹配一个$后跟一个数字的字符
注意,你还可以匹配一个不可打印的字符, 如tabs \t, 换行 \n,回车符 \r。
修饰符
我们正在学习如果编写一个正则表达式,但是忘记了一个基本概念:修饰符
正则表达式通常是/abc/这样的形式,其中匹配模式由两个/分隔。我们可以在它们的最后指定一个以下这些值的标志(也可以将它们组合使用)。
g (global): 第一个匹配后不返回结果,在上一次匹配结果之后继续检索,最后返回所有匹配项(全局匹配)。m (multi-line):启用时^和 $ 将匹配行的开头和结尾,而不是整个字符串。i (insensitive): 使整个表达式不区分大小写(for instance /aBc/i would match AbC)
es6新增
y (sticky):作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配结果的下一个位置开始。不同之处在于,g修饰符只要剩余位置中存在匹配就行,而y修饰符会确保匹配从剩余位置的第一个位置开始,这也就是“粘连”的涵义。
vars=’aaa_aa_a’;varr1=/a /g;varr2=/a /y;r1.exec(s);//[‘aaa’]r2.exec(s);//[‘aaa’]r1.exec(s);//[‘aa’]r2.exec(s);//nullvarr=/a _/y;//tryagainr.exec(s);//[‘aaa_’]r.exec(s);//[‘aa_’]r.sticky//true
u (Unicode):“Unicode”模式,用来正确处理大于\uFFFF的Unicode字符。也就是说,可以正确处理4个字节的UTF-16编码。
vars=’??’;/^.$/.test(s);//false/^.$/u.test(s);//true
s:匹配意字符,我们知道点(.)特殊字符代表任意字符,但是“行终止符”除外(eg.\n,\r,行分割符,段分隔符),s修饰符可包含所有,这被称为dotAll模式,即点(dot)代表一切字符。
vars=’??’;/.*/s.test(s);//true中级语法分组和捕获—??()
a(bc) 括号为创建一个值为bc的捕获组
a(?:bc)* 使用?:禁用捕获组(非捕获组)
要理解?:则需要理解捕获分组和非捕获分组的概念:
()表示捕获分组,()会把每个分组里的匹配的值保存起来,使用$n(n是一个数字,表示第n个捕获组的内容);
(?:)表示非捕获分组,和捕获分组唯一的区别在于,非捕获分组匹配的值不会保存起来。
es6新增
a(?< foo >bc) 使用?<foo>给这个捕获组命名。
如果为捕获组命名(使用?<foo>), 我们将能够使用匹配结果的groups中查找捕获组的值,键值就是组名。
当我们从字符串或者数据中提取信息的时候,此运算符非常有用。在使用多个捕获组匹配数据时,
我们将使用匹配结果的索引来访问它们的值($n),也可以具名组groups.<name>访问
varstring=’1999-12-31′;constmatchObj=string.match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/);//[“1999-12-31″,”1999″,”12″,”31″,index:0,input:”1999-12-31″,groups:{day:”31″,month:”12″,year:”1999”}]constnewStr=string.replace(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/,’$<day>/$<month>/$<year>’)//31/12/1999constnewStr2=string.replace(/(\d{4})-(\d{2})-(\d{2})/,’$3/$2/$1′)//31/12/1999//在正则表达式内部也可以使用“具名组匹配”\k<组名>constRE_TWICE=/^(?<word>[a-z] )!\k<word>$/RE_TWICE.test(‘abc!abc’)//trueRE_TWICE.test(‘abc!ab’)//false中括号—??[]
[abc] 匹配a或b或c, 等同于a|b|c
[a-c] 与上述一致
[a-fA-F0-9] 匹配一个十六进制字符,不区分大小写。
[0-9]% 匹配一个%前为0到9的字符串
[^a-zA-Z] 匹配一个没有从a-z或者A到Z的字母。这种情况下,^用作表示否定。
需要注意的是,在中括号表达式中,所有特殊字符(包括反斜杠\)都会失去它们特殊的功能,因此,不要使用“转义”功能
贪婪和懒匹配(Greedy and Lazy match)
量词( * {})是贪婪的匹配,所以它们会尽可能地通过提供的文本扩展匹配。
例如,使用<. > 来匹配 <div>simple div</div>,它会返回整个文本<div> simple div</div>
为了仅匹配一个div标签,我们可以使用?来使它lazy match
<. ?> 匹配<和>内包含的一个或者多个字符,根据需要进行扩展。
那么,更好的正则方案应该避免使用., 赞成使用更严格的模式:
<[^<>] > 匹配<和>内包含的任何字符。高级语法边界??—??\b and \B\babc\b abc前后都无字符, 即执行仅限整个单词匹配
\b 表示边界(类似于^和$)的位置,其中一侧是单词字符(如\w),而另一侧不是单词字符(例如,它可能是字符串的开头或空格字符 eg: \b123)。
它同样有否定,\B。这匹配\b所有不匹配的位置,如果我们找到完全被单词字符包围的匹配模式, 则可以匹配。
\Babc\B 执行abc左右都被字符包围匹配返回引用—??\1
([abc])\1 使用\1返回与第一个捕获组相同的匹配项进行匹配 == ([abc])([abc])
([abc])([de])\2\1 与上述一致,使用\2,\1返回与第二个捕获组,第一个捕获组相同的匹配项进行匹配 == ([abc])([de])([de])([abc]) , 以此类推
(?< foo >[abc])\k< foo > 我们将名称foo放入捕获组中,可以用\k引用它,结果与第一个正则一致 == ([abc])([abc])
前瞻(前置断言)和后瞻(后置断言)—??(?=) and (?<=)
firefox 目前不兼容,遇到过一次,请注意
d(?=r) 仅当d后跟r时才匹配d,但r不会成为整个正则表达式的一部分
(?<=r)d 仅当d前为r时才匹配d,但r不会成为整个正则表达式的一部分
你当然也可以使用否定运算符。
d(?!r) 仅当d后不是r时才匹配d,但r不会成为整个正则表达式的一部分
(?<!r)d 仅当d前不是r时才匹配d,但r不会成为整个正则表达式的一部分
用法介绍
注:pattern 为RegExp的实例, str 为String的实例
用法说明返回值regexp.test(str)判断str是否包含匹配结果包含返回true,不包含返回falseregexp.exec(str)根据regexp对str进行正则匹配返回匹配结果数组,如匹配不到返回null —与match的区别在于返回匹配信息更全str.match(regexp)根据regexp对str进行正则匹配返回匹配结果数组,如匹配不到返回nullstr.replace(regexp, newSubStr \ function)根据regexp / string对str进行正则匹配,把匹配结果替换为newSubStr \ function 的返回值返回替换后的字符串【原字符串不变】str.search(regexp)根据regexp对str进行正则匹配返回第一次匹配的位置str.split(regexp)以regexp为分隔符,对str切割为数组返回切割后的数组test/exec 注意事项
如果正则表达式设置了全局标志 /g,test() 的执行会改变正则表达式 lastIndex 属性。连续的执行 test()方法,后续的执行将会从 lastIndex 处开始匹配字符串,(exec() 同样改变正则本身的 lastIndex 属性值).
下面的实例表现了这种行为:
constdigits=/\d /g;digits.test(“Helloworld!123”);//truedigits.test(“321”);//falsedigits.test(“321”);//true
你可以这样 hack:
constdigits=/\d /g;digits.test(“Helloworld!123”);//truedigits.lastIndex=0;digits.test(“321”);//truedigits.lastIndex=0;digits.test(“321″);//true
详情参考:MDN
replace详解语法str.replace(regexp|substr,newSubStr|function)
参数
a:匹配项
b:匹配的捕获组
若无捕获组则无此参数,若多个捕获组则多个参数 b,c,d,e…;
若一个捕获组重复多次,则该捕获组的参数为最后一次匹配结果。例如:(\d)
c:匹配项在原字符串中的索引
d:原字符串
最后两个参数永远为 匹配项索引和原字符串
regexp (pattern)
一个RegExp对象或者其字面量。该正则所匹配的内容会被第二个参数的返回值替换掉。
substr (pattern)
一个要被 newSubStr 替换的字符串。其被视为一整个字符串,而不是一个正则表达式。仅仅是第一个匹配会被替换。
newSubStr (replacement)
用于替换掉第一个参数在原字符串中的匹配部分的字符串
function(a, b, c, d) (replacement)
一个用来创建新子字符串的函数,该函数的返回值将替换掉第一个参数匹配到的结果。
如果你对 replace 还有困惑,可以看看下面的例题
总结
正如您所见,正则表达式应用领域很广,我确信你的开发生涯中至少见过一次以上规则,下面是它的应用列表:
数据验证(例如,检查时间字符串的格式是否正确)数据抓取(尤其是网络抓取,查找包含特定单词集的所有页面,最终按特定顺序排列)数据包装(将数据从“原始”格式转换为其他格式)字符串分析(例如,捕获所有url get参数,捕获一组括号内的文本)字符串替换(例如,即使在代码会话中使用一个公共IDE来将Java或C类)转换为相应的JSON对象{–替换“;”与“,”使其为小写,避免类型声明等)。语法高亮、文件重命名、packet sniffing和许多其他涉及字符串的应用程序(其中数据不需要是文本的)
Have fun and do not forget to recommend the article if you liked it ??
附录:replace例题将下面两处空缺补全://define(function(window){functionfn(str){this.str=str;}fn.prototype.format=function(){vararg=____;returnthis.str.replace(____,function(a,b){returnarg[b]||”;})};window.fn=fn;})(window);//use(function(){vart=newfn(‘<p><ahref=”{0}”>{1}<a><span>{2}</span></p>’);console.log(t.format(‘http://www.yonyou.com’,’yonyou’,’Welcome’));})();//这里就不给答案了,如果你理解了replace用法,这太easy了。通过正则将 87654321 整数转为 货币 $87,654,321’87654321′.replace(/(\d) ?(?=(\d{3}) (?!\d))/g,function(a,b,c,d){returnd<2?(“$” a “,”):(a “,”);})//$87,654,321//请深入理解replace和正则后再理解该题’87654321′.replace(/(\d{1,3})(?=(\d{3}) $)/g,function(a,b,c,d){returnd<2?(“$” a “,”):(a “,”);})//$87,654,321’87654321′.replace(/\d{1,3}(?=(\d{3}) $)/g,’$&,’)//$&为匹配项;$1,$2…为捕获组//87,654,321密码强度正则,最少6位,包括至少1个大写字母,1个小写字母,1个数字/(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])^[0-9A-Za-z]{6,}$/.test(‘w44Y4S’)//前面三个前置断言,针对开头^项的约束/^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])/.test(‘w44sYw’)参考资料Regex tutorial??—??A quick cheatsheet by examples正则表达式中?=和?:和?!的理解[ JS 进阶 ] test, exec, match, replaceES6标准入门(第3版)—— 阮一峰A regular expression surprise in JavaScript