一道小小的題目引發(fā)對javascript支持正則表達式相關(guān)方法的探討

本文發(fā)布在我的博客一道小小的題目引發(fā)對javascript支持正則表達式相關(guān)方法的探討
許可協(xié)議: 署名-非商業(yè)性使用-禁止演繹 4.0 國際 轉(zhuǎn)載請保留原文鏈接及作者蹬昌。扮超、


以前對于正則是非常懼怕的逾苫,因為看不懂和學不會声怔。但最近項目中頻繁的使用到了正則堂鲤,因此強迫自己去學習了解,慢慢的體會到了他的魅力與強大。當然學習正則初入門的時候有些枯燥難懂演怎,但越學越覺得輕松。本文不準備說關(guān)于正則本身的事兒避乏,而是說一說關(guān)于javascript中關(guān)于正則的幾個方法中被很多人忽略的地方爷耀。

工具

說到正則,很多人都是從抄到改到自己寫拍皮,這個過程可能有時候很漫長歹叮。如一些工具能幫助你快速分析和學習正則,那么學習的過程你肯定要輕松得多铆帽。下面我推薦兩個我經(jīng)常使用的正則在線可視化工具咆耿,正則可視化工具圖解符合鐵路圖規(guī)律(其實不明白什么是鐵路一樣很容易看懂,只是一些細微的地方和我們的常規(guī)思維有點差別)爹橱。

  • regexper 我最常用的一個萨螺,個人覺得UI做得比其他好
  • regulex 備選,他有一個很舒心的功能愧驱,可以提供一段js慰技,嵌套到你的網(wǎng)站,生成正則可視化圖

一道小小的題目

這道題目是在群里日常閑聊時组砚,公司同事拋出來的吻商,具體是出自哪里本人沒去考察。先先說說題目:

寫一個方法把一個數(shù)字末尾的連續(xù)0變成9惫确,如1230000變成1239999

一道很簡單的題目手报,直接正則就能搞定,也許你會寫:

function zoreToNine(num){
    return (num + '').replace(/0/g,9);
}
//或者
function zoreToNine(num){
    return (num + '').replace(/[1-9]0+$/,9);
}

這也是此題的陷阱所在改化,按照上面的方法掩蛤,1023000就會被轉(zhuǎn)化成1923999,這樣是不符合要求的陈肛,所以改進一下:

function zoreToNine(num){
    return (num + '').replace(/[1-9]0+$/,function($1){
        return $1.replace(/0/g,9);
    });
}
zoreToNine(1223000); //1223999
zoreToNine(1023000); //1023999

關(guān)于這個問題的解決方案@微醺歲月同學提供了一種揍鸟,位置匹配的方法,簡單了很多句旱,厲害阳藻!

"12300100000".replace(/0(?=(0+$)|\b)/g,9); //12300199999

當然解決問題的方法很多,不一定非要用正則谈撒,還完全可以使用純算術(shù)的方法實現(xiàn)腥泥,大家有興趣可以嘗試,閑話少說進入這次的主題:javascript支持正則表達式相關(guān)方法啃匿,注意并不是正則對象的方法蛔外。
上述方法使用了正則蛆楞,有趣的是在回調(diào)函數(shù)里有一個$1,這個$1到底是什么夹厌?所有的匹配規(guī)則匹配后都有$1這個變量么豹爹?...一連串的問題,以前我從來沒有去追探過矛纹,趁著昨個比較空閑臂聋,去追探了一番,并在今天整理了一下或南,寫下此文記錄孩等。

主角

javascript中正則對象有三個方法:testexeccompile迎献,但是此次的主角并不是它們瞎访!我們討論的是能夠使用正則表示的相關(guān)方法:search腻贰、match吁恍、replacesplit,注意它們都是String對象的方法播演,使用它們必須要是String類型.

replace(rule[regexp/substr], replacement)

replace是一個用于替換字符串的方法冀瓦,雖然看似簡單,但是它隱藏的機關(guān)也是常常被人忽略写烤。具體分析一下它的特點:
它接收兩個參數(shù)
無副作用不影響原始變量
返回被改變的字符串(一定是字符串類型)

定義一些變量翼闽,方便全文取用。

let a = '12309800', b = '12309800[object Object]', b = '12309800{}';

參數(shù)rule

在一般情況洲炊,rule參數(shù)一般是正則感局、字符串、數(shù)字暂衡。
如果是字符串询微,將會在匹配到第一個符合條件的目標,結(jié)束方法狂巢;
如果是正則撑毛,則按照正則的規(guī)則進行匹配

//匹配第一個0替換成5
a.replace(0,5); //'12359800'
//匹配所有的0替換成5
a.replace(/0/g,5); //'12359855'

參數(shù)replacement

在一般情況,replacement參數(shù)是字符串唧领、數(shù)字藻雌、者回調(diào)。

包含$的字符串

當參數(shù)rule為正則斩个,并且正則至少包含有一對完整的()時胯杭,如果replacement包含有$的字符串,那么對于$n(n為大于0的整數(shù)受啥,n的長度取決于正則中括號的對數(shù))做个,會被解析成一個變量。但是也僅僅只是作為一個變量,無法在字符串中進行計算叁温,此時更類似特別的字符串模板變量再悼。

一般情況下,$n中n的長度取決于正則中括號的對數(shù)膝但,$1表示第1對括號匹配的結(jié)果冲九,$2表示第2對匹配的結(jié)果...在正則所有的括號對中,左括號出現(xiàn)在第幾個位置(或者說從左往右)跟束,則它就是第幾對括號莺奸,以此類推。姑且我們把這種規(guī)則成為正則匹配分割規(guī)則(ps:這完全是我自己取的一個名字冀宴,方便文章后面使用和記憶)灭贷。

a.replace(0,'$0'); //'123$09800'
a.replace(/00/g,'$0'); //'123098$0'
a.replace(/[1-9]0+$/,'$1'); //'12309$1'
a.replace(/([1-9](0+$))/,'$1'); //'12309800',此時$1為[1-9](0+$)匹配到的內(nèi)容略贮,$2為0+$匹配到的內(nèi)容
a.replace(/([1-9])(0+$)/,'$1'); //'123098'甚疟,此時$1為[1-9]匹配到的內(nèi)容,$2為0+$匹配到的內(nèi)容
a.replace(/([1-9])(0+$)/,'$1*$2'); //'123098*00'逃延,此處的$1和$2不會安照期待的情況進行乘法計算览妖,要進行計算可以用回調(diào)

請注意:雖然目前參數(shù)replacement中攜帶有$n仍然能正常使用,但是這種方式已經(jīng)不被規(guī)范所推薦揽祥,更應(yīng)該使用回調(diào)來完成這個操作讽膏。這一點謝謝@lucky4同學的指出

如果正則中包含有全局匹配標志(g),那么每次匹配的都符合上述規(guī)則

回調(diào)函數(shù)

先看例子:

a.replace(/[1-9]0+$/,function(){
    console.log(arguments); //["800",5,"12309800"]拄丰、
});
a.replace(/([1-9])0+$/,function(){
    console.log(arguments); //["800","8",5,"12309800"]
});
a.replace(/([1-9])(0+$)/,function(){
    console.log(arguments); //["800","8","00",5,"12309800"]
});
a.replace(/(([1-9])(0+$))/,function(){
    console.log(arguments); //["800","800","8","00",5,"12309800"]
});

回調(diào)函數(shù)的arguments數(shù)組部分組成:[完整匹配的字符串,$1,$2,...,$n,匹配的開始位置,原始字符串],$1...$n表示每個括號對的匹配府树,規(guī)則和前面的相同。
所以有一下規(guī)律:

let arr = [...arguments], len = arr.length;
(len >= 3) === true;
arr[0] = 完整匹配的字符串;
arr[len-2] = 匹配的開始位置;
arr[len-1] = 原始字符串;

注意:除了匹配的開始位置是Number類型外料按,其余的都是String類型

非常規(guī)類型參數(shù)

如果參數(shù)類型不是上述兩種情況奄侠,會發(fā)生什么呢?看看下面的例子:

a.replace(0,null); //123null9800
a.replace(0,undefined); //123null9800
a.replace(0,[]); //1239800
a.replace(0,Array); //1230,3,123098009800
b.replace({},5); //123098005
c.replace({},5); //'12309800{}'
a.replace(0,{}); //123[object Object]9800
a.replace(0,Object); //12309800

由上面的例子可以看出站绪,如果非正則也非字符串遭铺,則有以下規(guī)則:
null變量,則會轉(zhuǎn)換成'null'字符串;
undefined變量恢准,則會轉(zhuǎn)換成'undefined'字符串;
[]變量魂挂,則會調(diào)用join()方法轉(zhuǎn)換成字符串,默認以,分割馁筐,值得注意的是空數(shù)組將會被轉(zhuǎn)換成空字符串(沒有任何字符)涂召,通常會被匹配源字符串的開始位置(默認開始位置為空字符串);
'Array'變量,則會先轉(zhuǎn)成成一個匹配的數(shù)組敏沉,形如[完整匹配的字符串,$1,$2,...,$n,匹配的開始位置,原始字符串],然后對它調(diào)用join()方法轉(zhuǎn)換成字符串果正,默認以,分割;
{}變量炎码,則會調(diào)用Object.protype.toString.call()方法把{}轉(zhuǎn)換成[object Object];
Object變量,則貌似什么都沒做

雖然可以傳入這些非正常參數(shù)秋泳,但大多數(shù)情況下這些類型的參數(shù)對實際是毫無意義的潦闲,所以不建議傳入以上類型的參數(shù)。同上面的正則匹配分割規(guī)則一樣迫皱,為了方便使用稱呼歉闰,姑且我把上面的轉(zhuǎn)換規(guī)則稱為正則匹配參數(shù)轉(zhuǎn)換規(guī)則

match(rule[regex/substr])

match方法可在字符串內(nèi)檢索指定的值,或找到一個或多個正則表達式的匹配卓起。
該方法類似indexOflastIndexOf和敬,但是它返回指定的值,而不是字符串的位置戏阅;

參數(shù)

參數(shù)的傳遞除了常規(guī)的正則和字符串以外昼弟,其余所有類型的參數(shù)都會按照上述的正則匹配參數(shù)轉(zhuǎn)換規(guī)則轉(zhuǎn)換成字符串形式來匹配。

返回值

返回值根據(jù)傳入的參數(shù)類型和規(guī)則的不同奕筐,返回的內(nèi)容不同舱痘,但總體來說,它是返回一個對象救欧,而不是索引衰粹,如果沒匹配到任何符合條件的字符串锣光,則返回null笆怠。

非全局匹配正則

如果匹配規(guī)則是一個非全局匹配規(guī)則,那么誊爹,它此時的返回值是一個偽數(shù)組對象(likeArr)蹬刷,形如:[一個展開的匹配到的字符串數(shù)組, 匹配到的字符串位置, 原始字符串]频丘,它有如下規(guī)律:

var likeArr = a.match(regex);
likeArr[0] = 匹配到的字符串;
likeArr[1...n] = 正則匹配分割規(guī)則匹配的字符串;
likeArr.index = 匹配到字符串的位置
likeArr.inupt = 原始字符串

看例子:

a.match(/[1-9]0+$/); //[0:'800',index:5,input:'12309800']
a.match(/([1-9])0+$/); //[0:'800',1:'8',index:5,input:'12309800']
a.match(/[1-9](0+$)/); //[0:'800',1:'00',index:5,input:'12309800']
a.match(/([1-9])(0+$)/); //[0:'800',1:'8',2:'00',index:5,input:'12309800']

全局匹配正則

如果匹配規(guī)則是一個全局匹配規(guī)則(正在攜帶有g(shù)標志)办成,那么,它此時的返回值是一個數(shù)組對象(arr)搂漠,形如:[匹配到的字符串數(shù)1,匹配到的字符串數(shù)2,匹配到的字符串數(shù)3];
看例子:

a.match(/[1-9]0/); //[0:'30',index:2,input:'12309800']
a.match(/[1-9]0/g); //[0:'30',1:'80']

search(rule[regex/substr])

search方法用于檢索字符串中指定的子字符串迂卢,或檢索與正則表達式相匹配的子字符串。
stringObject中第一個與rule相匹配的子串的起始位置桐汤。如果沒有找到任何匹配的子串而克,則返回-1
注意:

  • search方法不執(zhí)行全局匹配怔毛,它將忽略標志g员萍。
  • 忽略regexplastIndex屬性,總是從字符串的開始進行檢索拣度,這意味著它總是返回stringObject的第一個匹配的位置

同樣碎绎,search可以傳入任何參數(shù)類型螃壤,它會遵循正則匹配參數(shù)轉(zhuǎn)換規(guī)則進行轉(zhuǎn)換

split(rule[regex/substr],len)

這個方法就不用多說,很常用的字符串分割方法筋帖。
第二個參數(shù)的作用就是限制返回值的長度奸晴,表示返回值的最大長度

當然,它依然可以傳入任何參數(shù)類型日麸,會遵循正則匹配參數(shù)轉(zhuǎn)換規(guī)則進行轉(zhuǎn)換

有一段加密的后的密碼蚁滋,我們需要分離出字符串'12a344gg333tt445656ffa6778ii99'中的前三組數(shù)字,通過某種計算才能得出正確的密碼

'12a344gg333tt445656ffa6778ii99'.split(/[a-zA-Z]+/g,3);//['12','334','333']

最后

寫了這么多赘淮,突然發(fā)現(xiàn)以前僅僅是在用這些方法辕录,了解得很不夠深入。越是學習才發(fā)現(xiàn)其中的奧秘梢卸!學無止境走诞,與諸君共勉!
以上內(nèi)容如有錯誤之處蛤高,希望諸君不吝指出蚣旱!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市戴陡,隨后出現(xiàn)的幾起案子塞绿,更是在濱河造成了極大的恐慌,老刑警劉巖恤批,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件异吻,死亡現(xiàn)場離奇詭異,居然都是意外死亡喜庞,警方通過查閱死者的電腦和手機诀浪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來延都,“玉大人雷猪,你說我怎么就攤上這事∥浚” “怎么了求摇?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長殊者。 經(jīng)常有香客問我与境,道長,這世上最難降的妖魔是什么幽污? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任嚷辅,我火速辦了婚禮,結(jié)果婚禮上距误,老公的妹妹穿的比我還像新娘簸搞。我一直安慰自己扁位,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布趁俊。 她就那樣靜靜地躺著域仇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪寺擂。 梳的紋絲不亂的頭發(fā)上暇务,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音怔软,去河邊找鬼垦细。 笑死,一個胖子當著我的面吹牛挡逼,可吹牛的內(nèi)容都是我干的括改。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼家坎,長吁一口氣:“原來是場噩夢啊……” “哼嘱能!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起虱疏,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤惹骂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后做瞪,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體对粪,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年穿扳,在試婚紗的時候發(fā)現(xiàn)自己被綠了衩侥。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡矛物,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出跪但,到底是詐尸還是另有隱情履羞,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布屡久,位于F島的核電站忆首,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏被环。R本人自食惡果不足惜糙及,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望筛欢。 院中可真熱鬧浸锨,春花似錦唇聘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至聪蘸,卻和暖如春宪肖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背健爬。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工控乾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人娜遵。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓阱持,卻偏偏與公主長得像,于是被迫代替她去往敵國和親魔熏。 傳聞我的和親對象是個殘疾皇子衷咽,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

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

  • 從匹配中返回值 Match 對象 成功的匹配總是返回一個 Match 對象, 這個對象通常也被放進 $/ 中, (...
    焉知非魚閱讀 1,800評論 0 1
  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學一百閱讀 3,237評論 0 4
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)蒜绽,斷路器镶骗,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • 作者:尹木子 十點五十五分鼎姊,我提前推開門,進了一...
    尹木子閱讀 225評論 0 1
  • 根據(jù)目前執(zhí)行狀況做一些調(diào)整 規(guī)則: 周 期:本期至2017年12月31日 監(jiān)督媒介:早睡早起微信群 使用工具:各...
    書童阿雷閱讀 417評論 0 1