[JS] 正則表達式(Regular Expression, regex) - PJCHENder

文章推薦指數: 80 %
投票人數:10人

[JS] 正則表達式(Regular Expression, regex). 'str'.match(/[0-9]+ ... Skiptomaincontent這個網站放置的是未發佈或未完整整理的筆記內容,若想檢視正式的筆記內容請到PJCHENder那些沒告訴你的小細節。

PJCHENderOfficialDocsBlogGitHubFacebookLinkedinSearchJavaScript[JS]regexOnthispage'str'.match(/[0-9]+/);//1次以上的數字,等同於"\d"'str'.match(/[A-Za-z]+/);//1次以上的英文字'str'.match(/[A-Za-z0-9_]+/);//1次以上的英數字含底線,等同於"\w"'str'.match(/.+/);//1次以上的任意字元*表示前一個字元可以是0個或多個,例如/ab*c/,因此ac,abc,abbbbc都符合規則。

+表示前一個字元可以是1個或多個,例如/a+b/,ab,aaaaab都符合規則。

?表示前一個字元可以是0個或1個^匹配輸入的開頭,例如/^a/,adog會符合,但cats中的a不會。

$匹配輸入的結尾,例如/t$/,eat會符合,但eaten中的t不會。

.用來表示任意字元[email protected]@MDN-JavaScriptGuidesRegularExpression@MDN-ReferenceIhateregex:可以找到許多常用的regex範例常用正規表達式建立正規式​正則表達式的規則稱作pattern。

在JavaScript中可以透過Regularexpressionliterals的方式或建構式的方式來建立regularexpressionspattern:Regularexpressionliterals​/***Regularexpressionliterals:script載入時即編譯*當pattern不會改變時,使用此方式定義pattern效能較好。

**/varre=/ab+c/;FunctionConstructor​/***FunctionconstructorforRegExpobject:程式執行過程才會被編譯*效能較差,適合用在regularexpressionpattern可能會改變時使用**/varre=newRegExp('ab+c');varmyRe=newRegExp('d(b+)d','g');Regularexpressionliterals效能較好,適合pattern不會改變的情況;FunctionConstructor效能較差,適合用在pattern可能動態改變的情況。

使用正規式​在JavaScript中可以使用正規式的函式包含RegExp.prototype.test():搜尋字串中是否有符合的部分,回傳true/false。

RegExp.prototype.exec():以陣列回傳字串中匹配到的部分,否則回傳null。

String.prototype.match():以陣列回傳字串中匹配到的部分,否則回傳null。

String.prototype.replace():尋找字串中匹配的部分,並取代之。

String.prototype.search():尋找字串中是否有符合的部分,有的話回傳index,否則回傳-1。

String.prototype.split():在字串根據匹配到的項目拆成陣列。

簡單來說,當你想要看字串是否包含某pattern時,使用test或search;想要更多的資訊(花較多耗效能),則使用exec或match。

String.prototype.replace():取代內容​使用String.prototype.replace(regex|substr,newSubstr)來置換內容,這個方法會回傳置換後的新字串,不會改變原本的字串://只接把regex寫在裡面newString=.replace(/

/g,'')//先建立regexletregex=newRegExp(wordToBeReplaced,'gi')letnewString=.replace(regex,'wordToReplace')/.../g:global的意思,找到之後會繼續往後配對 /.../i:caseinsensitive的意思/*找到第一個就不往後找*/'banana'.replace(/na/,'NA');//'baNAna'/*把n後面和後面的字元*/'banana'.replace(/n./,'NA');//'baNAna''banana'.replace(/na/g,'NA');//'baNANA''banana'.replace(/na/gi,'NA');//'baNANA'搭配括號和$n​varre=/(\w+)\s(\w+)/;varstr='JohnSmith';varnewStr=str.replace(re,'$2,$1');console.log(newStr);搭配replacerfunction​functionreplacer(match,p1,p2,p3,offset,string){//p1isnon-digits,p2digits,andp3non-alphanumericsreturn[p1,p2,p3].join('-');}varnewString='abc12345#$*%'.replace(/([^\d]*)(\d*)([^\w]*)/,replacer);console.log(newString);//abc-12345-#$*%String.prototype.match:尋找並取出內容​String.prototype.match@MDN使用String.prototype.match(regexp)這個方法來判斷給的字串當中是否有符合該regexppattern的內容,有的話以陣列回傳,沒有的話回傳null。

如果這個regexp的pattern不包含g標籤,那麼str.match()回傳的結果和RegExp.exec()是一樣的,在回傳的陣列中會包含:input屬性:原本被解析的字串index屬性:第一個被找的字串的index值所有配對的結果/*不包含g的話,結果和RegExp.exec()一樣*/letmatchedResult='Anappleaday,keepsappleaway.'.match(/(a.)(p.)e/);//['apple','ap','pl',index:3,input:'Anappleaday,keepsappleaway.']如果pattern中包含g的話,那麼回傳的陣列中會直接是整個被matched到的字:/*包含g的話,會直接回傳配對到的結果*/letmatchedResult='Anappleaday,keepsappleaway.'.match(/(a.)(p.)e/g);//['apple','apple']若給入一個非regexp的物件,則會自動透過newRegExp(obj)轉換;若沒有代入任何參數的話,則會得到帶有空字串的陣列([""])。

使用範例​每個()會變成一個$letmatchedResult='Anappleaday'.match(/(a.)(p.)e/);RegExp.$1;//apRegExp.$2;//pl'banana'.match(/(.)(a)/g);//['ba','na','na']//$1=['b','n','n']//$2=['a','a','a']//"/"是特殊字元要用反斜線'2017/05/16'.match(/(.*)\/(.*)\/(.*)/);//['2017/05/16','2017','05','16']'2017/05/16'.match(/.*\/.*\/.*/);//['2017/05/16']/***擷取網址中的內容**/leturl='https://www.ptt.cc/bbs/CodeJob/M.1513840968.A.F93.html'lettimestamp=url.match(/\/M\.(.+)\.A/)console.log(timestamp[1])//1513840968//resultoftimestamp['/M.1513840968.A',//該正規式會匹配到的內容'1513840968',//透過match()選取到的內容index:30,//從哪個index開始批配到input:'https://www.ptt.cc/bbs/CodeJob/M.1513840968.A.F93.html'//輸入的內容]搭配filter篩選結果​搭配Array.prototype.filter我們就可以根據使用者輸入的內容(wordToMatch)來從cities中篩選資料:functionfindMatch(wordToMatch,cities){returncities.filter((place)=>{/***g:globalsearch*i:caseinsensitivesearch**/letregex=newRegExp(wordToMatch,'gi');returnplace.city.match(regex)||place.state.match(regex);});}[JS30]Day06:AJAXTypeAheadString.prototype.search():檢驗字串是否包含​varstr='heyJudE';varre=/[A-Z]/g;varre2=/[.]/g;console.log(str.search(re));//returns4,whichistheindexofthefirstcapitalletter"J"console.log(str.search(re2));//returns-1cannotfind'.'dotpunctuationRegExp.prototype.test():檢驗字串是否包含​//判斷是不是數值/^[0-9]+$/.test()//returnTrue/FalseRegExp.prototype.exec:尋找並取出內容​letregexp=/d(b+)d/g;letmatchedResult=regexp.exec('cdbbdbsbz');//['dbbd','bb',index:1,input:'cdbbdbsbz']//透過while取出所有配對到的結果while((arr=regexp.exec('tablefootball,foosball'))!==null){console.log(`Found${arr[0]}.Nextstartsat${regexp.lastIndex}.`);//expectedoutput:"Foundfoo.Nextstartsat9."//expectedoutput:"Foundfoo.Nextstartsat19."}使用RegExp.$1來取得配對到的值​這是非標準的使用方式,請勿在正式環境使用:varre=/(\w+)\s(\w+)/;varstr='JohnSmith';str.replace(re,'$2,$1');//"Smith,John"RegExp.$1;//"John"RegExp.$2;//"Smith"RegExp.$1-$9@MDN群組與命名群組(GroupandNamedCaptureGroup)​透過()可以把配對到的內容分成不同組別(group)放到陣列中:constregexp=/(\w+)\.jpg/;constmatched=regexp.exec('Filename:cat.jpg');//[//'cat.jpg',//'cat',//index:11,//input:'Filename:cat.jpg',//groups:undefined//]constfileName=matched[1];//car配對到的內容會被放在陣列當中,因此可以透過解構賦值(destructuringassignment)的方式,將想要的內容取出:const[match,year,month,day]=regexpWithGroup.exec(str);命名群組(namedgroup)​❗命名群組(namedgroup)的這個功能屬於ES2018須留意相容性。

在ES2018中則可以使用(?…)為組別命名,所有命名的組別會被放在名為groups物件內://使用(?)來為組別命名constregexp=/(?\d{4})-(?\d{2})-(?\d{2})/;constmatch=regexp.exec('2020-03-04');console.log(match.groups);//{year:"2020",month:"03",day:"04"}console.log(match.groups.year);//2020console.log(match.groups.month);//03console.log(match.groups.day);//04如果命名群組中的內容沒有被匹配到的話,該群組groups的屬性仍會存在,只是會得到undefined的值。

使用?:這可以把group起來,但不需要用到的內容隱藏起來(shygroup)。

搭配replace使用​在replace後面可以接function,在這個function則可以直接取得配對到的內容和分組的結果:conststr='War&Peace';constresult=str.replace(/(?War)&(?Peace)/,function(match,group1,group2,offset,string){returngroup2+'&'+group1;},);console.log(result);//→Peace&WarSampleCode​範例程式碼@repl.it特殊字元(character)​RegularExpressReference@MDN標籤(flag)​regex=/hello/;//區分大小寫,匹配"hello","hello123","123hello123","123hello",但不匹配"hell0","Hello"regex=/hello/i;//不區分大小寫"hello","HelLo","123HelLO"regex=/hello/g;//全域搜尋dotAllFlag,/s​ES2019新增/s的標籤,過去.可以用來匹配除了換行符號以外(\n,\r)的所有字元://過去.可以匹配到除了「換行符號」以外的所有字元console.log(/./.test('\n'));//→falseconsole.log(/./.test('\r'));//→false過去雖然可以使用[\w\W]來匹配到換行符號,但這不是最好的做法:console.log(/[\w\W]/.test('\n'));//→trueconsole.log(/[\w\W]/.test('\r'));//→true在ES2019中,只要最後有標記/s的標籤,如此.將也能夠匹配到換行符號:console.log(/./s.test('\n'));//→trueconsole.log(/./s.test('\r'));//→true普通字元//​varregex=/a/;varregex=/is/;反斜線\​/*在「非」特殊字元前面使用反斜線時,表示要把反斜線後的字當作是特殊字元*/varregex=/\b/;//b原本不是特殊字元,這個b要當成特殊字元/*在特殊字元前面使用反斜線時,表示要把反斜線後的字當作是「非」特殊字元*/varregex=/if\(true/;//(原本是特殊字元,但這裡要當成非特殊字元varregex=/1\+2=3/;//+原本是特殊字元,但這裡要當成非特殊字元任意一個字元.​可以用來匹配除了換行符號(\n)以外的所有字元:varregex=/a.man/;//a*man都會match,例如"acman","awman",但"a\nman"無法匹配。

varregex=/.a/;//任何一個字元後加上a多個字元[]​//小寫a或大寫Avarregex=/[aA]/;//匹配所有不是a或A的字varregex=/[^aA]/;//a,e,i,o,u都會matchvarregex=/[aeiou]/;//英文字母varregex=/[a-z]/;//所有小寫的字母,從小寫a到小寫zvarregex=/[A-Z]/;//所有大寫的字母,從大寫A到大寫Zvarregex=/[a-zA-Z]/;//所有英文字母//數字5~8varregex=/[5-8]/;括號():套用到所有​varregex=/^a|^the|^an/;//套用到裡面所有的varregex=/^(a|the|an)/;//等同於不是(除了)^​/*不是a都會match*/varregex=/[^a]/;/*不是數字都會match*/varregex=/[^0-9]/;多個字元縮寫​keywords:\d,\w,\s,\b,\D,\W,\S​\d:digit,[0-9]\w:word,包含英文大小寫、數字、底線,[A-Za-z0-9_]\s:space,包含space,tab,formfeed,linefeed,[\f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]\D:不是digit,等同於[^\d]\W:不是word[^\w]\S:不是space[^\s]/*所有word+e*/varregex=/\we/;/*連續兩個任意的數值*/varregex=/\d\d/;/*句子中結尾為s的單字*/varregex=/s\b/;varregex=/\b[a-z]/g;//句子中各個單字的第一個字母其他特殊字元​\t:tab\b:wordboundary,用來比對單字和單字間的空白,/s\b/則會比對句子中最一個字母是s的單字Wordboundary\b,\B​透過\b可以配對wordboundary,wordboundary指的是一個字元的前後沒有其他任何字元。

要注意\b和[\b]是不一樣的,[\b]是用來配對backspace。

//is這個單字才會被選到,Th`is`的is不會letmatchedResult='Thisisanapple.'.match(/\bis\b/);//['is',index:5,input:'Thisisanapple.']相反地,\B則是non-wordboundary,包含:Beforethefirstcharacterofthestring,ifthefirstcharacterisnotawordcharacter.Afterthelastcharacterofthestring,ifthelastcharacterisnotawordcharacter.BetweentwowordcharactersBetweentwonon-wordcharactersTheemptystring//使用\B會配對到This中的isletmatchedResult='Thisisanapple.'.match(/\Bis/);//['is',index:2,input:'Thisisanapple.']出現次數*+?{}{,}​keywords:*,+,?,{次數},{最少次數,最多次數}​*:任意次數,等同於{0,}+:至少一次(後面要跟著),等同於{1,}?:零或一次(有或沒有),等同於{0,1}{次數}*{最少次數,最多次數}**varregex=/abc/;//找到符合"abc"varregex=/ab*c/;//*表示前一個單字可以是0個或多個,因此ac,abc,abbbbc都符合規則varregex=/n?a/;//n可有可無varregex=/a{2}/;//a要2次,所以會是avarregex=/a{2,4}/;//a介於2次到4次之間varregex=/a{2,}/;//2次以上的a都可以,大括號後面不要有空格varregex=/(hello){4}/;//4次的hello,hellohellohellohellovarregex=/\d{3}/;//3次的數字開頭與結尾​keywords:^​^開頭$結尾/*以A開頭的字才會匹配到*//^A/gm.test('Abc');//true/^A/gm.test('bac');//false/*開頭有He*/varregex=/^He/;/*結尾有llo*/varregex=/llo$/;/*開頭He結尾llo中間任意字元可以有任意次數*/varregex=/^He.*llo$/;或|​//and或android,match到`and`roid就不match`android`varregex=/and|android/;//match到android還是會matchandvarregex=/android|and/;LookAroundAssertions​keywords:x(?=y),x(?!y)​Lookaheadassertions:x(?=y),x(?!y)Lookbehindassertions:(?<=y)x,(?]*,匹配除了>以外的其他內容varregex=/]*>(.*?)/g;筆記來源​5/1719:30承億主講regularexpression@線上讀書會RegularExpressReference@MDN-GlobalObjectReferenceRegularExpressionGuide@MDN-JavaScriptGuidesregexCheatSheet@GistNewJavaScriptFeaturesThatWillChangeHowYouWriteRegex@SmashingMagazinePrevious[JS]proxyNext[JS]set建立正規式使用正規式String.prototype.replace():取代內容String.prototype.match:尋找並取出內容String.prototype.search():檢驗字串是否包含RegExp.prototype.test():檢驗字串是否包含RegExp.prototype.exec:尋找並取出內容使用RegExp.$1來取得配對到的值群組與命名群組(GroupandNamedCaptureGroup)命名群組(namedgroup)搭配replace使用SampleCode特殊字元(character)標籤(flag)普通字元//反斜線任意一個字元.多個字元[]括號():套用到所有不是(除了)^多個字元縮寫出現次數*+?{}{,}開頭與結尾或|LookAroundAssertionsBackreferences貪婪模式(GreedyMode)常用例子西元生日身份證字號GMAIL網址(URL)HTML標籤筆記來源



請為這篇文章評分?