JavaScript 正則表達式(2)


JavaScript正則表達式(1)中,我們學習了如何聲明一個正則對象以及正則里常用的一些元字符奋救,正則對象的方法和字符串里的正則方法岭参。下面,我們來一起學習入門拓展的JavaScript正則表達式


正則表達式的反向引用###

在正則表達式中尝艘,括號能有‘記住’他們包含的子表達式匹配的文本演侯。所以,如果我們運用反向引用的方法去匹配類似于AA背亥,疊字類型的文本秒际,就簡單很多了,當然狡汉,反向引用的作用不止如此娄徊。具體代碼如下:

var reg =/(c.(t))(123)\1\2\3/ig;
var text = '------cat123catt123-------';
text.match(reg);//["cat123catt123"]

\1是匹配第一個括號里面的,\2是匹配第一個括號里面嵌套的括號盾戴,\3是匹配最后一個括號寄锐。


正則表達式的分組匹配###

分組匹配運用括號的原理和反向引用類似,只是反向引用作用在正則表達式‘內(nèi)部’尖啡,分組匹配在正則表達式‘外部’橄仆,語言的形容是蒼白無力的,請看下面的具體代碼:

var reg =/(c.(t))(123)\1\2\3/ig;
var text = '------cat123catt123-------';
text.match(reg);
console.log(RegExp.$1);//cat
console.log(RegExp.$2);//t
console.log(RegExp.$3);//123

在上述衅斩,我們知道可以用()保留我們想要的數(shù)據(jù)盆顾,并通過一些方法,比如$1畏梆,\1取得您宪,如果你不想讓()保留,可以使用(?:···)的方式奠涌,讓這個括號變?yōu)?strong>非捕獲性括號蚕涤。這樣,正則就不會記錄里面的數(shù)據(jù)了铣猩。


正則表達式中的環(huán)視(lookaround)###

在了解環(huán)視之前揖铜,我們一起來思考一個問題,比如有這么一串數(shù)字28000000000达皿,看起來是不是很累天吓?所以一般情況下,我們需要給它加上,峦椰,就像這樣28,000,000,000龄寞,但是問題來了,應該如何給這個字符串加上,呢汤功,我們知道是從右往左物邑,一次3個數(shù)字,加一個,,但是正則表達式都是從左往右解析的色解。聰明的你一定想到了茂嗓,我們以左邊至少有一個數(shù)字,右邊是3的倍數(shù)個數(shù)字的規(guī)則去匹配科阎,不就行了嗎述吸?所以,我們嘗試寫下了如下的正則表達式:

var reg = /([0-9]+)([0-9][0-9][0-9])+/g;
var text = '28000000000'
while(text!== text.replace(reg,'$1,$2')){
  text = text.replace(reg,'$1,$2')
};
console.log(text)//28,000,000,000

很顯然锣笨,我們得到了我們想要的結(jié)果蝌矛,但是是不是顯得不太優(yōu)雅?至少我認為是的错英,分析一下代碼入撒,我們發(fā)現(xiàn),正則匹配是只要匹配過去之后就不會回頭再去匹配(下一次匹配開始的地方是上一次匹配結(jié)束的地方)椭岩,所以要通過一個while循環(huán)茅逮,一直遍歷到無法匹配為止。
所以簿煌,在這個時候,環(huán)視的概念就顯得尤為重要鉴吹,它的概念是什么呢姨伟?
環(huán)視是不匹配任何字符,只匹配文本中的特定位置的一種結(jié)構(gòu)豆励。與^夺荒,\b$有點類似良蒸。既然是一種結(jié)構(gòu)技扼,那么理所應當?shù)模?strong>匹配的時候并不會占用字符嫩痰。
不占用字符是一種怎么樣的概念呢剿吻?具體代碼如下:

var reg = /moon(?=burn)/;
var reg2 = /moon(?:burn)/;
var text = 'moonburn';
var text1 = 'moonbUrn'
console.log(text.match(reg));//["moon", index: 0, input: "moonburn"]
console.log(text.match(reg2));//["moonburn", index: 0, input: "moonburn"]
console.log(text1.match(reg));//null

通過上述代碼,應該很容易就可以發(fā)現(xiàn)串纺,環(huán)視的作用丽旅,使用環(huán)視的方式就是(?=···),而moon(?=burn)的意思就是說纺棺,匹配一個moon然后后面是burn的字符串榄笙,moon(?:burn)的意思其實和moon(?=burn)理解起來是差不多的,但是還是有一個很大的區(qū)別祷蝌,就是上面提出的茅撞,用環(huán)視的方式進行匹配,匹配的字符本身不會被算為占用的字符,也就是說米丘,用moon(?=burn)剑令,匹配到n的時候,遇到了環(huán)視蠕蚜,然后判斷后續(xù)是否符合環(huán)視的規(guī)則尚洽,如果符合,返回moon靶累,如果不符合腺毫,返回null,而moon(?:burn)的意思是挣柬,匹配到n之后潮酒,繼續(xù)向后匹配bu邪蛔,r急黎,n,如果都匹配成功,返回moonburn(因為burn也是匹配項)侧到,失敗勃教,返回null。這就是環(huán)視最大的優(yōu)點匹配的時候并不會占用字符匠抗。

環(huán)視的種類####

當然故源,為了需要,環(huán)視也不僅僅只有(?=···)一種汞贸,還有以下的:

類型 正則表達式 匹配成功的條件
肯定順序環(huán)視 (?=···) 子表達式能夠匹配右側(cè)文本
否定順序環(huán)視 (?!···) 子表達式不能匹配右側(cè)文本

環(huán)視大家差不多已經(jīng)有所了解了绳军,那么回到一開始的那個例子,通過環(huán)視矢腻。如何更優(yōu)雅的給一串數(shù)字加上,呢门驾?具體代碼如下:

var reg =/([0-9])(?=([0-9][0-9][0-9])+(?![0-9]))/g;
var text = '28000000000';
text.replace(reg,'$1,');//28,000,000,000

是不是通過環(huán)視就把while循環(huán)去掉了,變得清爽了很多多柑?確實奶是,環(huán)視的作用確實蠻大的,希望大家能夠理解竣灌,熟練運用并掌握诫隅。


字符組簡記法

在上述例子中,我們用[0-9]來匹配一個數(shù)字帐偎,其實在JavaScript中(很多其他語言也是一樣的)逐纬,用\d來表示匹配一個數(shù)字,所以削樊,上面的代碼可以改為:

var reg =/(\d)(?=(\d\d\d)+(?!\d))/g;
var text = '28000000000';
text.replace(reg,'$1,');//28,000,000,000

是不是更加清爽了豁生?在我看來兔毒,[0-9]\d是完全等價的,只是\d的寫法更簡單甸箱,明了一些育叁。這種就叫做字符組簡記法,當然芍殖,不僅僅只有\d一個豪嗽,更多的如下:

字符 匹配對象 注釋
\d 數(shù)字 等價于[0-9]
\D 非數(shù)字字符 等價于[^\d]
\w 單詞中的字符 等價于[a-zA-Z0-9_](至少在JavaScript是這樣)
\W 非單詞字符 等價于[^\w]
\s 空白字符 等價于[ \f\n\r\t\v]
\S 非空白字符 等價于[^\s]

JavaScript中正則的引擎

首先,要知道豌骏,正則的引擎種類繁多龟梦,但是大致可以分為2個大類,一種是NFA窃躲,一種是DFA计贰。JavaScript用的是NFA引擎。通過簡單的代碼判斷:

var reg = /nfa|nfa not/g;
var text = 'nfa not';
text.match(reg)//["nfa"];

可以得知蒂窒,JavaScript是傳統(tǒng)型的NFA躁倒,不是POSIX NFA

在了解不同引擎的差異之前洒琢,我們可以先來了解一下它們的共同點秧秉。以下共同點適用于所有引擎:

  1. 優(yōu)先選擇最左端(最開頭)的位置匹配。
  1. 標準的匹配量詞*,+,?{m.n}是匹配優(yōu)先的衰抑。

下面 開始討論第一條規(guī)則象迎,優(yōu)先選擇最左端(最開頭)的位置匹配
舉個例子,例如以下情況:

var reg = /cat/g;
var text = '123catt45678cat'
text.search(reg)//3

text中停士,滿足reg的位置有2個挖帘,分別是3,12完丽,因為優(yōu)先選擇左端的位置恋技,所以匹配了3位置的cat

再來一個例子:

var reg = /cat|dog|monkey/g;
var text = '123monkeydogcatt45678cat'
text.search(reg)//3

這個例子很簡單逻族,告訴我們蜻底,正則表達式的匹配是所有的匹配項都會嘗試一遍,哪怕monkey項在正則的最后面聘鳞,也會最先匹配薄辅。
下面開始討論第二條規(guī)則,標準的匹配量詞*,+,?{m.n}是匹配優(yōu)先的抠璃。
關于上述的匹配量詞站楚,都是匹配優(yōu)先的,匹配優(yōu)先是個什么意思呢搏嗡?比如窿春,當我們用了+來進行匹配的時候拉一,當匹配到一個滿足條件之后,他會繼續(xù)往下匹配旧乞,一直匹配到無法匹配為止蔚润。如果我們看到匹配出來的結(jié)果不是最大匹配項,那么一定是因為最大匹配項的情況下無法滿足后續(xù)的匹配規(guī)則尺栖,就減少匹配項從而滿足后續(xù)項嫡纠,這種全部匹配的過程,就是匹配優(yōu)先的過程延赌。舉個例子:

var reg = /[0-9]+0/g;
var text = '12340567890123';
text.match(reg);//["12340567890"]

這個是匹配成功了除盏,一開始的[0-9]+就把1234567890123全部匹配完了(匹配優(yōu)先,就是這么厲害皮胡!不服不行3占铡),但是匹配完了之后屡贺,發(fā)現(xiàn)無法滿足后面的匹配項0,沒有辦法蠢棱,只能退回一個,看看能不能滿足甩栈,于是[0-9]+的匹配項變成了``123456789012泻仙,發(fā)現(xiàn)還是不行,重復上述過程······一直退回到123456789量没,后面匹配到0,滿足了玉转!搞定收工!返回了["12340567890"]殴蹄,細心的你究抓,一定是發(fā)現(xiàn)了,其實在前面的12340也是滿足這個正則的袭灯,并且是排在了更加靠左的地方刺下,但是卻被忽略了,為什么稽荧?因為有關匹配量詞的引擎內(nèi)部的計算方法就是這樣的橘茉,或者說因為**匹配優(yōu)先**,而選擇了后面的符合條件的1234567890`姨丈。
為了鞏固大家對匹配優(yōu)先的理解畅卓,我準備趁熱打鐵,再來一個可能大家會混淆的例子(希望是我多慮了):

var reg = /[0-9]+([0-9]+)/g;
var text = '12340567890123';
text.match(reg);
RegExp.$1;//是多少呢蟋恬?

先允許我賣個關子翁潘,先來分析一波,想一下匹配優(yōu)先的原則歼争,一開始的[0-9]+text全部匹配完了拜马,然后慢慢退回箱歧,退回一個3([0-9]+)之后,滿足了一膨,完成走人......可能有人會想呀邢,后面一個也是+啊為什么才給它一個數(shù)字呢淮悼,沒辦法咱筛,先來先服務嘛约谈,勉強給你一個滿足就不錯了撤逢,你還要幾個捡鱼?還要啥自行車碘裕?所以RegExp.$1的值是3更啄。

答對了嗎诫给?如果答對了巷蚪,那你應該對匹配優(yōu)先了解透徹了病毡,如果沒有答對或者很猶豫,那請你在看看前文吧屁柏。因為萬丈高樓平地起啦膜,很多復雜的正則表達式都是從這個開始的√视鳎基礎尤為重要僧家。



JavaScript 正則表達式(1)
JavaScript 正則表達式(2)
JavaScript 正則表達式(3)
JavaScript 正則表達式(4)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市裸删,隨后出現(xiàn)的幾起案子八拱,更是在濱河造成了極大的恐慌,老刑警劉巖涯塔,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肌稻,死亡現(xiàn)場離奇詭異,居然都是意外死亡匕荸,警方通過查閱死者的電腦和手機爹谭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來每聪,“玉大人旦棉,你說我怎么就攤上這事齿风∫┦恚” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵救斑,是天一觀的道長童本。 經(jīng)常有香客問我,道長脸候,這世上最難降的妖魔是什么穷娱? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任绑蔫,我火速辦了婚禮,結(jié)果婚禮上泵额,老公的妹妹穿的比我還像新娘配深。我一直安慰自己,他們只是感情好嫁盲,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布篓叶。 她就那樣靜靜地躺著,像睡著了一般羞秤。 火紅的嫁衣襯著肌膚如雪缸托。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天瘾蛋,我揣著相機與錄音俐镐,去河邊找鬼。 笑死哺哼,一個胖子當著我的面吹牛佩抹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播取董,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼匹摇,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了甲葬?” 一聲冷哼從身側(cè)響起廊勃,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎经窖,沒想到半個月后坡垫,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡画侣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年冰悠,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片配乱。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡溉卓,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出搬泥,到底是詐尸還是另有隱情桑寨,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布忿檩,位于F島的核電站尉尾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏燥透。R本人自食惡果不足惜沙咏,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一辨图、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧肢藐,春花似錦故河、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瞻讽,卻和暖如春鸳吸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背速勇。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工晌砾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烦磁。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓养匈,卻偏偏與公主長得像,于是被迫代替她去往敵國和親都伪。 傳聞我的和親對象是個殘疾皇子呕乎,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容