舒适提示:文章很长很长,保持耐心,必要时能够跳着看,固然用来查也是不错的。javascript
正则啊,就像一座灯塔,当你在字符串的海洋不知所措的时候,总能给你一点思路;正则啊,就像一台验钞机,在你不知道用户提交的钞票真假的时候,总能帮你一眼识别;正则啊,就像一个手电筒,在你须要找什么玩意的时候,总能帮你get你要的东西... html
—— 节选自 Stinson 同窗的语文排比句练习《正则》java
欣赏了一段文学节选后,咱们正式来梳理一遍JS中的正则,本文的首要目的是,防止我常常忘记正则的一些用法,故梳理和写下来增强熟练度和用做参考,次要目的是与君共勉,若有纰漏,请不吝赐教,良辰谢过。es6
本文既然取题为“一条龙”,就要对得起”龙”,故将包括正则原理、语法一览、JS(ES5)中的正则、ES6对正则的扩展、实践正则的思路,我尽可能深刻尽可能浅出地去讲这些东西(搞得好像真能深刻浅出同样的),若是你只想知道怎么应用,那么看第2、3、五部分,基本就能知足你的需求了,若是想掌握JS中的正则的,那么仍是委屈你跟着个人思路来吧,嘿嘿嘿!正则表达式
在一开始用正则的时候,就以为神奇,计算机到底是怎么根据一个正则表达式来匹配字符串的?直到后来我遇到了一本书叫《计算理论》,看到了正则、DFA、NFA的概念和相互间的联系,才有一些恍然小悟的意思。算法
但若是真的要从原理上吃透正则表达式,那么恐怕最好的方式是:编程
首先去找一本专门讲正则的书去看看,O’REILLY的“动物总动员”系列里就有;数组
再本身实现一个正则引擎。app
而本文的重点在于JS中正则的应用,故原理仅做简单介绍(由于我也没写过正则引擎,也不深刻),一来大体“糊弄下”像我同样的好奇宝宝们对正则原理的疑惑,二来知道一些原理方面基本的知识,对于理解语法和写正则是大有裨益的。编程语言
为何正则能有效,由于有引擎,这和为何JS能执行同样,有JS引擎,所谓正则引擎,能够理解为根据你的正则表达式用算法去模拟一台机器,这台机器有不少状态,经过读取待测的字符串,在这些状态间跳来跳去,若是最后停在了“终结状态”(Happy Ending),那么就Say I Do,不然Say You Are a Good Man。如此将一个正则表达式转换为一个可在有限的步数中计算出结果的机器,那么就实现了引擎。
正则的引擎大体可分为两类:DFA和NFA
DFA (Deterministic finite automaton) 肯定型有穷自动机
NFA (Non-deterministic finite automaton) 非肯定型有穷自动机,大部分都是NFA
这里的“肯定型”指,对于某个肯定字符的输入,这台机器的状态会肯定地从a跳到b,“非肯定型”指,对于某个肯定字符的输入,这台机器可能有好几种状态的跳法;这里的“有穷”指,状态是有限的,能够在有限的步数内肯定某个字符串是被接受仍是发好人卡的;这里的“自动机”,能够理解为,一旦这台机器的规则设定完成,就能够自行判断了,不要人看。
DFA引擎不须要进行回溯,因此匹配效率通常状况下要高,可是它并不支持捕获组,因而也就不支持反向引用和$
这种形式的引用,也不支持环视(Lookaround)、非贪婪模式等一些NFA引擎特有的特性。
若是想更详细地了解正则、DFA、NFA,那么能够去看一下《计算理论》,而后你能够根据某个正则表达式本身画出一台自动机。
这一小节对于你理解正则表达式颇有用,尤为是明白什么是字符,什么是位置。
在上面的“笑声”字符串中,一共有8个字符,这是你能看到的,还有9个位置,这是聪明的人才能看到的。为何要有字符还要有位置呢?由于位置是能够被匹配的。
那么进一步咱们再来理解“占有字符”和“零宽度”:
若是一个子正则表达式匹配到的是字符,而不是位置,并且会被保存到最终的结果中,那个这个子表达式就是占有字符的,好比/ha/
(匹配ha
)就是占有字符的;
若是一个子正则匹配的是位置,而不是字符,或者匹配到的内容不保存在结果中(其实也能够看作一个位置),那么这个子表达式是零宽度的,好比/read(?=ing)/
(匹配reading,可是只将read放入结果中,下文会详述语法,此处仅仅举例用),其中的(?=ing)
就是零宽度的,它本质表明一个位置。
占有字符是互斥的,零宽度是非互斥的。也就是一个字符,同一时间只能由一个子表达式匹配,而一个位置,却能够同时由多个零宽度的子表达式匹配。举个栗子,好比/aa/
是匹配不了a
的,这个字符串中的a只能由正则的第一个a字符匹配,而不能同时由第二个a匹配(废话);可是位置是能够多个匹配的,好比/\b\ba/
是能够匹配a
的,虽然正则表达式里有2个表示单词开头位置的\b
元字符,这两个\b
是能够同时匹配位置0(在这个例子中)的。
注意:咱们说字符和位置是面向字符串说的,而说占有字符和零宽度是面向正则说的。
这两个词可能在搜一些博文或者资料的时候会遇到,这里作一个解释先:
控制权是指哪个正则子表达式(可能为一个普通字符、元字符或元字符序列组成)在匹配字符串,那么控制权就在哪。
传动是指正则引擎的一种机制,传动装置将定位正则从字符串的哪里开始匹配。
正则表达式当开始匹配的时候,通常是由一个子表达式获取控制权,从字符串中的某一个位置开始尝试匹配,一个子表达式开始尝试匹配的位置,是从前一子表达匹配成功的结束位置开始的。
举一个栗子,read(?=ing)ing\sbook
匹配reading book
,咱们把这个正则当作5个子表达式read
、(?=ing)
、ing
、\s
、book
,固然你也能够吧read
看作4个单独字符的子表达式,只是咱们这里为了方便这么看待。read
从位置0开始匹配到位置4,后面的(?=ing)
继续从位置4开始匹配,发现位置4后面确实是ing,因而断言匹配成功,也就是整一个(?=ing)
就是匹配了位置4这一个位置而已(这里更能理解什么是零宽了吧),而后后面的ing
再从位置4开始匹配到位置7,而后\s
再从位置7匹配到位置8,最后的book
从位置8匹配到位置12,整一个匹配完成。
说了那么多,咱们把本身当作一个正则引擎,一步一步以最小的单位——“字符”和“位置”——去看一下正则匹配的过程,举几个栗子。
正则表达式:easy 源字符串:So easy
匹配过程:首先由正则表达式字符e
取得控制权,从字符串的位置0开始匹配,遇到字符串字符‘S’,匹配失败,而后正则引擎向前传动,从位置1开始尝试,遇到字符串字符‘o’,匹配失败,继续传动,后面的空格天然也失败,因而从位置3开始尝试匹配,成功匹配字符串字符‘e’,控制权交给正则表达式子表达式(这里也是一个字符)a
,尝试从上次匹配成功的结束位置4开始匹配,成功匹配字符串字符‘a’,后面一直如此匹配到‘y’,而后匹配完成,匹配结果为easy
。
正则:^(?=[aeiou])[a-z]+$ 源字符串:apple
首先这个正则表示:匹配这样一个从头至尾完整的字符串,这整一个字符串仅由小写字母组成,而且以a、e、i、o、u这5个字母任一字母开头。
匹配过程:首先正则的^
(表示字符串开始的位置)获取控制权,从位置0开始匹配,匹配成功,控制权交给(?=[aeiou])
,这个子表达式要求该位置右边必须是元音小写字母中的一个,零宽子表达式相互间不互斥,因此从位置0开始尝试匹配,右侧是字符串的‘a’,符合所以匹配成功,因此(?=[aeiou])
匹配此处的位置0匹配成功,控制权交给[a-z]+
,从位置0开始匹配,字符串‘apple’中的每一个字符都匹配成功,匹配到字符串末尾,控制权交回正则的$
,尝试匹配字符串结束位置,成功,至此,整个匹配完成。
正则1:{.*} 正则2:{.*?} 源字符串:{233}
这里有两个正则,在限定符(语法会讲什么是限定符)后面加?
符号表示忽略优先量词,也就是非贪婪匹配,这个栗子我剥得快一点。
首先开头的{
匹配,两个正则都是同样的表现。
正则1的.*
为贪婪匹配,因此一直匹配余下字符串'233}',匹配到字符串结束位置,只是每次匹配,都记录一个备选状态,为了之后回溯,每次匹配有两条路,选择了匹配这条路,但记一下这里还能够有不匹配这条路,若是前面死胡同了,能够退回来,此时控制权交还给正则的}
,去匹配字符串结束位置,失败,因而回溯,意思就是说前面的.*
你吃的太多了,吐一个出来,因而控制权回给.*
,吐出一个}
(实际上是用了前面记录的备选状态,尝试不用.*
去匹配'}'),控制权再给正则的}
,此次匹配就成功了。
正则2的.*?
为非贪婪匹配,尽量少地匹配,因此匹配'233}'的每个字符的时候,都是尝试不匹配,可是一但控制权交还给最后的}
就发现出问题了,赶忙回溯乖乖匹配,因而每个字符都如此,最终匹配成功。
云里雾里?这就对了!能够移步去下面推荐的博客看看:
想详细了解贪婪和非贪婪匹配原理以及获取更多正则相关原理,除了看书以外,推荐去一个CSDN的博客 雁过无痕-博客频道 - CSDN.NET ,讲解得很详细和透彻
正则的语法相信许多人已经看过deerchao写的30分钟入门教程,我也是从那篇文字中入门的,deerchao从语法逻辑的角度以.NET正则的标准来说述了正则语法,而我想从新组织一遍,以便于应用的角度、以JS为宿主语言来从新梳理一遍语法,这将便于咱们把语言描述翻译成正则表达式。
下面这张一览图(可能须要放大),整理了经常使用的正则语法,而且将JS不支持的语法特性以红色标注出来了(正文将不会描述这些不支持的特性),语法部分的详细描述也将根据下面的图,从上到下,从左到右的顺序来梳理,尽可能不啰嗦。
为何这里要加简单2个字,由于在正则中,\d
、\w
这样的叫元字符,而{n,m}
、(?!exp)
这样的也叫元字符,因此元字符是在正则中有特定意义的标识,而这一小节讲的是简单的一些元字符。
.
匹配除了换行符之外的任意字符,也便是[^\n]
,若是要包含任意字符,可以使用(.|\n)
\w
匹配任意字母、数字或者下划线,等价于[a-zA-Z0-9_]
,在deerchao的文中还指出可匹配汉字,可是\w
在JS中是不能匹配汉字的
\s
匹配任意空白符,包含换页符\f
、换行符\n
、回车符\r
、水平制表符\t
、垂直制表符\v
\d
匹配数字
\un
匹配n,这里的n是一个有4个十六进制数字表示的Unicode字符,好比\u597d
表示中文字符“好”,那么超过\uffff
编号的字符怎么表示呢?ES6的u修饰符会帮你。
a*
表示字符a连续出现次数 >= 0 次
a+
表示字符a连续出现次数 >= 1 次
a?
表示字符a出现次数 0 或 1 次
a{5}
表示字符a连续出现次数 5 次
a{5,}
表示字符a连续出现次数 >= 5次
a{5,10}
表示字符a连续出现次数为 5到10次 ,包括5和10
匹配某个位置的表达式都是零宽的,这是主要包含两部分,一是定位符,匹配一个特定位置,二是零宽断言,匹配一个要知足某要求的位置。
定位符有如下几个经常使用的:
\b
匹配单词边界位置,准确的描述是它匹配一个位置,这个位置先后不全是\w
能描述的字符,因此像\u597d\babc
是能够匹配“好abc”的。
^
匹配字符串开始位置,也就是位置0,若是设置了 RegExp 对象的 Multiline 属性,^
也匹配 'n' 或 'r' 以后的位置
$
匹配字符串结束位置,若是设置了RegExp 对象的 Multiline 属性,$
也匹配 'n' 或 'r' 以前的位置
零宽断言(JS支持的)有如下两个:
(?=exp)
匹配一个位置,这个位置的右边能匹配表达式exp,注意这个表达式仅仅匹配一个位置,只是它对于这个位置的右边有要求,而右边的东西是不会被放进结果的,好比用read(?=ing)
去匹配“reading”,结果是“read”,而“ing”是不会放进结果的
(?!exp)
匹配一个位置,这个位置的右边不能匹配表达式exp
咱们常常会表达“或”的含义,好比这几个字符中的任意一个都行,再好比匹配5个数字或者5个字母都行等等需求。
字符簇可用来表达字符级别的“或”语义,表示的是方括号中的字符任选一:
[abc]
表示a、b、c这3个字符中的任意一个,若是字母或者数字是连续的,那么能够用-
连起来表示,[b-f]
表明从b到f这么多字符中任选一个
[(ab)(cd)]
并不会用来匹配字符串“ab”或“cd”,而是匹配a、b、c、d、(、)这6个字符中的任一个,也就是想表达“匹配字符串ab或者cd”这样的需求不能这么作,要这么写ab|cd
。但这里要匹配圆括号自己,讲道理是要反斜杠转义的,可是在方括号中,圆括号被当成普通字符看待,即使如此,仍然建议显式地转义
分歧用来表达表达式级别的“或”语义,表示的是匹配|
左右任一表达就可:
ab|cd
会匹配字符串“ab”或者“cd”
会短路,回想下编程语言中逻辑或的短路,因此用(ab|abc)
去匹配字符串“abc”,结果会是“ab”,由于竖线左边的已经知足了,就用左边的匹配结果表明整个正则的结果
有时候咱们想表达“除了某些字符以外”这样的需求,这个时候就要用到反义
\W
、\D
、\S
、\B
用大写字母的这几个元字符表示就是对应小写字母匹配内容的反义,这几个依次匹配“除了字母、数字、下划线外的字符”、“非数字字符”、“非空白符”、“非单词边界位置”
[^aeiou]
表示除了a、e、i、o、u外的任一字符,在方括号中且出如今开头位置的^
表示排除,若是^
在方括号中不出如今开头位置,那么它仅仅表明^
字符自己
其实你在上面的一些地方已经看到了圆括号,是的,圆括号就是用来分组的,括在一对括号里的就是一个分组。
上面讲的大部分是针对字符级别的,好比重复字母 “A” 5次,能够用A{5}
来表示,可是若是想要字符串“ABC”重复5次呢?这个时候就须要用到括号。
括号的第一个做用,将括起来的分组当作一个总体看待,因此你能够像对待字符重复同样在一个分组后面加限定符,好比(ABC){5}
。
分组匹配到的内容也就是这个分组捕获到的内容,从左往右,以左括号为标志,每一个分组会自动拥有一个从1开始的编号,编号0的分组对应整个正则表达式,JS不支持捕获组显示命名。
括号的第二个做用,分组捕获到的内容,能够在以后经过\分组编号
的形式进行后向引用。好比(ab|cd)123\1
能够匹配“ab123ab”或者“cd123cd”,可是不能匹配“ab123cd”或“cd123ab”,这里有一对括号,也是第一对括号,因此编号为捕获组1,而后在正则中经过\1
去引用了捕获组1的捕获的内容,这叫后向引用。
括号的第三个做用,改变优先级,好比abc|de
和(abc|d)e
表达的彻底不是一个意思。
任何在正则表达式中有做用的字符都建议转义,哪怕有些状况下不转义也能正确,好比[]
中的圆括号、^
符号等。
优先级从高到低是:
转义 \
括号(圆括号和方括号)(), (?:), (?=), []
字符和位置
竖线 |
在限定符中,除了{n}
确切表示重复几回,其他的都是一个有下限的范围。
在默认的模式(贪婪)下,会尽量多的匹配内容。好比用ab*
去匹配字符串“abbb”,结果是“abbb”。
而经过在限定符后面加问号?
能够进行非贪婪匹配,会尽量少地匹配。用ab*?
去匹配“abbb”,结果会是“a”。
不带问号的限定符也称匹配优先量词,带问号的限定符也称忽略匹配优先量词。
其实正则的匹配选项有不少可选,不一样的宿主语言环境下可能各有不一样,此处就JS的修饰符做一个说明:
加g修饰符:表示全局匹配,模式将被应用到全部字符串,而不是在发现第一个匹配项时中止
加i修饰符:表示不区分大小写
加m修饰符:表示多行模式,会改变^
和$
的行为,上文已述
JS中的正则由引用类型RegExp表示,下面主要就RegExp类型的建立、两个主要方法和构造函数属性来展开,而后会说起String类型上的模式匹配,最后会简单罗列JS中正则的一些局限。
一种是用字面量的方式建立,一种是用构造函数建立,咱们始终建议用前者。
//建立一个正则表达式 var exp = /pattern/flags; //好比 var pattern=/\b[aeiou][a-z]+\b/gi; //等价下面的构造函数建立 var pattern=new RegExp("\\b[aeiou][a-z]+\\b","gi");
其中pattern能够是任意的正则表达式,flags部分是修饰符,在上文中已经阐述过了,有 g、i、m 这3个(ES5中)。
如今说一下为何不要用构造函数,由于用构造函数建立正则,可能会致使对一些字符的双重转义,在上面的例子中,构造函数中第一个参数必须传入字符串(ES6能够传字面量),因此字符\
会被转义成\,所以字面量的\b
会变成字符串中的\\b
,这样很容易出错,贼多的反斜杠。
var matches=pattern.exec(str); 接受一个参数:源字符串 返回:结果数组,在没有匹配项的状况下返回null
结果数组包含两个额外属性,index表示匹配项在字符串中的位置,input表示源字符串,结果数组matches第一项即matches[0]
表示匹配整个正则表达式匹配的字符串,matches[n]
表示于模式中第n个捕获组匹配的字符串。
要注意的是,第一,exec()永远只返回一个匹配项(指匹配整个正则的),第二,若是设置了g
修饰符,每次调用exec()会在字符串中继续查找新匹配项,不设置g
修饰符,对一个字符串每次调用exec()永远只返回第一个匹配项。因此若是要匹配一个字符串中的全部须要匹配的地方,那么能够设置g
修饰符,而后经过循环不断调用exec方法。
//匹配全部ing结尾的单词 var str="Reading and Writing"; var pattern=/\b([a-zA-Z]+)ing\b/g; var matches; while(matches=pattern.exec(str)){ console.log(matches.index +' '+ matches[0] + ' ' + matches[1]); } //循环2次输出 //0 Reading Read //12 Writing Writ
var result=pattern.test(str); 接受一个参数:源字符串 返回:找到匹配项,返回true,没找到返回false
RegExp构造函数包含一些属性,适用于做用域中的全部正则表达式,而且基于所执行的最近一次正则表达式操做而变化。
RegExp.input
或RegExp["$_"]
:最近一次要匹配的字符串
RegExp.lastMatch
或RegExp["$&"]
:最近一次匹配项
RegExp.lastParen
或RegExp["$+"]
:最近一次匹配的捕获组
RegExp.leftContext
或RegExp["$`"]
:input字符串中lastMatch以前的文本
RegExp.rightContext
或RegExp["$'"]
:input字符串中lastMatch以后的文本
RegExp["$n"]
:表示第n个捕获组的内容,n取1-9
上面提到的exec和test都是在RegExp实例上的方法,调用主体是一个正则表达式,而以字符串为主体调用模式匹配也是最为经常使用的。
在字符串上调用match方法,本质上和在正则上调用exec相同,可是match方法返回的结果数组是没有input和index属性的。
var str="Reading and Writing"; var pattern=/\b([a-zA-Z]+)ing\b/g; //在String上调用match var matches=str.match(pattern); //等价于在RegExp上调用exec var matches=pattern.exec(str);
接受的参数和match方法相同,要么是一个正则表达式,要么是一个RegExp对象。
//下面两个控制台输出是同样的,都是5 var str="I am reading."; var pattern=/\b([a-zA-Z]+)ing\b/g; var matches=pattern.exec(str); console.log(matches.index); var pos=str.search(pattern); console.log(pos);
var result=str.replace(RegExp or String, String or Function); 第一个参数(查找):RegExp对象或者是一个字符串(这个字符串就被看作一个平凡的字符串) 第二个参数(替换内容):一个字符串或者是一个函数 返回:替换后的结果字符串,不会改变原来的字符串
第一个参数是字符串
只会替换第一个子字符串
第一个参数是正则
指定g
修饰符,则会替换全部匹配正则的地方,不然只替换第一处
第二个参数是字符串
可使用一些特殊的字符序列,将正则表达式操做的值插进入,这是很经常使用的。
$n
:匹配第n个捕获组的内容,n取0-9
$nn
:匹配第nn个捕获组内容,nn取01-99
$`
:匹配子字符串以后的字符串
$'
:匹配子字符串以前的字符串
$&
:匹配整个模式得字符串
$$
:表示$
符号自己
第二个参数是一个函数
在只有一个匹配项的状况下,会传递3个参数给这个函数:模式的匹配项、匹配项在字符串中的位置、原始字符串
在有多个捕获组的状况下,传递的参数是模式匹配项、第一个捕获组、第二个、第三个...最后两个参数是模式的匹配项在字符串位置、原始字符串
这个函数要返回一个字符串,表示要替换掉的匹配项
基于指定的分隔符将一个字符串分割成多个子字符串,将结果放入一个数组,接受的第一个参数能够是RegExp对象或者是一个字符串(不会被转为正则),第二个参数可选指定数组大小,确保数组不会超过既定大小。
JS(ES5)中不支持如下正则特性(在一览图中也能够看到):
匹配字符串开始和结尾的A和Z锚
向后查找(因此不支持零宽度后发断言)
并集和交集类
原子组
Unicode支持(uFFFF以后的)
命名的捕获组
单行和无间隔模式
条件匹配
注释
ES6对正则作了一些增强,这边仅仅简单罗列如下主要的3点,具体能够去看ES6
ES5中构造函数是不能接受字面量的正则的,因此会有双重转义,可是ES6是支持的,即使如此,仍是建议用字面量建立,简洁高效。
加了u
修饰符,会正确处理大于\uFFFF
的Unicode,意味着4个字节的Unicode字符也能够被支持了。
// \uD83D\uDC2A是一个4字节的UTF-16编码,表明一个字符 /^\uD83D/u.test('\uD83D\uDC2A') // false,加了u能够正确处理 /^\uD83D/.test('\uD83D\uDC2A') // true,不加u,当作两个unicode字符处理
加了u
修饰符,会改变一些正则的行为:
.
本来只能匹配不大于\uFFFF
的字符,加了u
修饰符能够匹配任何Unicode字符
Unicode字符新表示法\u{码点}
必须在加了u
修饰符后才是有效的
使用u
修饰符后,全部量词都会正确识别码点大于0xFFFF
的Unicode字符
使一些反义元字符对于大于\uFFFF
的字符也生效
y修饰符的做用与g修饰符相似,也是全局匹配,开始从位置0开始,后一次匹配都从上一次匹配成功的下一个位置开始。
不一样之处在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始。
因此/a/y
去匹配"ba"
会匹配失败,由于y修饰符要求,在剩余位置第一个位置(这里是位置0)开始就要匹配。
ES6对正则的增强,能够看这篇
应用正则,通常是要先想到正则(废话),只要看到和“找”相关的需求而且这个源是能够被字符串化的,就能够想到用正则试试。
通常在应用正则有两类状况,一是验证类问题,另外一类是搜索、提取、替换类问题。验证,最多见的如表单验证;搜索,以某些设定的命令加关键词去搜索;提取,从某段文字中提取什么,或者从某个JSON对象中提取什么(由于JSON对象能够字符串化啊);替换,模板引擎中用到。
验证类问题是咱们最常遇到的,这个时候其实源字符串长什么样咱们是不知道,鬼知道萌萌哒的用户会作出什么邪恶的事情来,推荐的方式是这样的:
首先用白话描述清楚你要怎样的字符串,描述好了以后,就开脑洞地想用户可能输入什么奇怪的东西,就是本身举例,拿一张纸可举一大堆的,有接受的和不接受的(这个是你知道的),这个过程当中可能你会去修改以前的描述;
把你的描述拆解开来,翻译成正则表达式;
测试你的正则表达式对你以前举的例子的判断是否是和你预期一致,这里就推荐用在线的JS正则测试去作,不要本身去一遍遍写了。
这类问题,通常咱们是知道源文本的格式或者大体内容的,因此在解决这类问题时通常已经会有一些测试的源数据,咱们要从这些源数据中提取出什么、或者替换什么。
找到这些手上的源数据中你须要的部分;
观察这些部分的特征,这些部分自己的特征以及这些部分周围的特征,好比这部分前一个符号必定是一个逗号,后一个符号必定是一个冒号,总之就是找规律;
考察你找的特征,首先能不能确切地标识出你要的部分,不会少也不会多,而后考虑下之后的源数据也是如此么,之后会不会这些特征就没有了;
组织你对要找的这部分的描述,描述清楚通过你考察的特征;
翻译成正则表达式;
测试。
终于絮絮不休写完了,1万多字有关JS正则的讲解,写完发现本身对正则的熟练又进了一步,因此推荐你们常常作作梳理,颇有用,而后乐于分享,于己于人都是大有裨益,感谢能看完的全部人。
我没有仔细地审稿,你们遇到什么问题,或者发现有什么纰漏之处,还望你们指出,留言就好。我会及时修改。