国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

我所理解的正則表達(dá)式

_Zhao / 2480人閱讀

摘要:關(guān)于,新手理解起來可能比較困難,尤其是一些很牛逼的預(yù)查正則表達(dá)式。非貪婪與貪婪的問題貪婪出現(xiàn)在這種不確定數(shù)量的匹配中,所謂的貪婪,表示正則表達(dá)式在匹配的時(shí)候,盡可能多的匹配符合條件的內(nèi)容。

學(xué)習(xí)了半年的正則表達(dá)式,也不能說一直學(xué)習(xí)吧,就是和它一直在打交道,如何用正則表達(dá)式解決自己的問題,并且還要考慮如何在匹配大量的文本時(shí)去優(yōu)化它。慢慢的覺得正則已經(jīng)成為自己的一項(xiàng)技能,逐漸的從一個(gè)正則表達(dá)式小白變成一個(gè)偽精通者。

那么,我不打算詳細(xì)介紹正則表達(dá)式的使用,或者說這篇文章并不是入門教程,所以如果你對正則表達(dá)式一無所知或者處于入門階段,建議你還是先去看看下面這些正則表達(dá)式入門的文章。

阮一峰老師的正則教程
MDN 正則介紹
胡子哥正則表達(dá)式 30 分鐘入門
阮一峰 ES6 正則表達(dá)式擴(kuò)展
百度百科 正則表達(dá)式 很詳細(xì),可以當(dāng)作手冊參考

當(dāng)然正則的教程很多,不限于此,如果你對正則已經(jīng)了解了,那么可以開始下面的內(nèi)容了,文章中可能還會(huì)涉及一些效率的問題

new RegExp 和 // 正則對象創(chuàng)建區(qū)別

如果寫過 Python 的同學(xué),都一定會(huì)知道 Python 中可以在字符串前面加個(gè)小寫的 r ,來表示防止轉(zhuǎn)義。防止轉(zhuǎn)義的意思就是說:str = r" " 等價(jià)于 str = " ",加了 r 會(huì)防止 被轉(zhuǎn)義。

為什么要介紹這個(gè),因?yàn)檫@就是 new RegExp// 的區(qū)別,因?yàn)槲覀冎涝谡齽t表達(dá)式中會(huì)頻繁的使用轉(zhuǎn)義字符 wsd 等,但是它們在內(nèi)存中的是以 wsd 存儲(chǔ)的,看個(gè)例子:

//推薦寫法
var regex1 = /w+/g;
regex1 // /w+/g
//RegExp 寫法
var regex2 = new RegExp("w+","g");
regex2 // /w+/g
//錯(cuò)誤寫法
var regex3 = new RegExp("w+","g");
regex3 // /w+/g

你也看出來了,錯(cuò)誤寫法只能匹配 wwwww 這樣的字符串,曾經(jīng)我就見過有人把他們弄混了,還說第一個(gè)第三個(gè)沒有區(qū)別。第二種方法的輸出,還是 /w+/g,中間還是要轉(zhuǎn)換,所以推薦第一種寫法。

當(dāng)然,還有比較奇葩的:

var regex4 = new RegExp(/w+/g);
regex4 // /w+/g

MSDN 上關(guān)于 RegExp 的介紹。

那么,如何能像 Python 的 r"" 那樣,實(shí)現(xiàn)一個(gè)防轉(zhuǎn)義的功能呢?我這里有一種很蹩腳的方法(僅供娛樂!):

var str1 = "dws";
str1; // "dws"
var str2 = /dws/;
str2.source; // "dws"

沒錯(cuò),就是 srouce,不知道 source 的同學(xué)快去面壁吧。(這方法確實(shí)很摳腳!)

i、g、m 修飾符

這幾個(gè)修飾符只是針對 JS 來說的,像 Python 中還有 re.S 表示 . 可以匹配換行符。

對于 i 表示忽略字母大小寫,不是很常用,因?yàn)樗泻芏嗵娲罚热纾?b>/[a-zA-Z]/ 可以用來替代 /[a-z]/i,至于兩者處理長文本的時(shí)間效率,我自己沒有研究過,不下定論。

使用 i 需要注意的地方,就是 i 會(huì)對正則表達(dá)式的每一個(gè)字母都忽略大小寫,當(dāng)我們需要部分單詞的時(shí)候,可以考慮一下/(?:t|T)he boy/

g 表示全局匹配,在印象中,可能很多人會(huì)覺得全局匹配就是當(dāng)使用 match 的時(shí)候,把所有符合正則表達(dá)式的文本全部匹配出來,這個(gè)用途確實(shí)很廣泛,不過 g 還有其他更有意思的用途,那就是 lastIndex 參數(shù)。

var str = "1a2b3c4d5e6f",
    reg = /dwd/g;
str.match(reg); //["1a2", "3c4", "5e6"]

為什么不包括2b3,4d5,因?yàn)檎齽t表達(dá)式匹配的時(shí)候,會(huì)用 lastIndex 來標(biāo)記上次匹配的位置,正常情況下,已經(jīng)匹配過的內(nèi)容是不會(huì)參與到下次匹配中的。帶有 g 修飾符時(shí),可以通過正則對象的 lastIndex 屬性指定開始搜索的位置,當(dāng)然這僅僅局限于函數(shù) exec 和 test(replace 沒研究過,沒聽說過可以控制 lastIndex,match 返回的是數(shù)組,無法控制 lastIndex),針對這個(gè)題目修改如下:

var str = "1a2b3c4d5e6f",
  reg = /dwd/g;
var a;
var arr = [];
while(a = reg.exec(str)){
  arr.push(a[0]);
  reg.lastIndex -= 1;
}
arr //["1a2", "2b3", "3c4", "4d5", "5e6"]

m 表示多行匹配,我發(fā)現(xiàn)很多人介紹 m 都只是一行略過,其實(shí)關(guān)于 m 還是很有意思的。首先,來了解一下單行模式,我們知道 JavaScript 正則表達(dá)式中的 . 是無法匹配 (換行,各個(gè)系統(tǒng)使用不一樣) 的,像 Python 提供 re.S 表示 . 可以匹配任意字符,包括 ,在 JS 中如果想要表示匹配任意字符,只能用[sS] 這種蹩腳的方式了(還有更蹩腳的 [dD],[.s])。這種模式叫做開啟或關(guān)閉單行模式,可惜 JS 中無法來控制。

多行模式跟 ^ $ 兩兄弟有關(guān),如果你的正則表達(dá)式?jīng)]有 ^$,即時(shí)你開啟多行模式也是沒用的。正常的理解/^123$/只能匹配字符串123,而開啟多行模式/^123$/g能匹配["123"," 123","123 "," 123 "],相對于 ^$ 可以匹配 了。

var str = "
a";
/^a/.test(str); //false
/^a/m.test(str); //true

有人說,m 沒用。其實(shí)在某些特殊的格式下,你知道你要匹配的內(nèi)容會(huì)緊接著 或以 結(jié)尾,這個(gè)時(shí)候 m 就非常有用,比如 HTTP 協(xié)議中的請求和響應(yīng),都是以 劃分每一行的,響應(yīng)頭和響應(yīng)體之間以 來劃分,我們需要匹配的內(nèi)容就在開頭,通過多行匹配,可以很明顯的提高匹配效率。

原理性的東西,我們還是要知道的,萬一以后會(huì)用到。

(?:) 和 (?=) 區(qū)別

在正則表達(dá)式中,括號(hào)不能亂用,因?yàn)槔ㄌ?hào)就代表分組,在最終的匹配結(jié)果中,會(huì)被算入字匹配中,而 (?:) 就是來解決這個(gè)問題的,它的別名叫做非捕獲分組。

var str = "Hello world!";
var regex = /Hello (w+)/;
regex.exec(str); //["Hello world", "world"]
var regex2 = /Hello (?:w+)/;
regex2.exec(str); //["Hello world"]
//replace 也一樣
var regex3 = /(?:ab)(cd)/
"abcd".replace(regex3,"$1") //"cd"

可以看到 (?:) 并不會(huì)把括號(hào)里的內(nèi)容計(jì)入到子分組中。

關(guān)于 (?=),新手理解起來可能比較困難,尤其是一些很牛逼的預(yù)查正則表達(dá)式。其實(shí)還有個(gè) (?!),不過它和 (?=) 是屬于一類的,叫做正向肯定(否定)預(yù)查,它還有很多別名比如零寬度正預(yù)測先行斷言。但我覺得最重要的只要記住這兩點(diǎn),預(yù)查和非捕獲。

預(yù)查的意思就是在之前匹配成功的基礎(chǔ)上,在向后預(yù)查,看看是否符合預(yù)查的內(nèi)容。正因?yàn)槭穷A(yù)查,lastIndex 不會(huì)改變,且不會(huì)被捕獲到總分組,更不會(huì)被捕獲到子分組。

var str = "Hello world!";
var regex = /Hello (?=w+)/;
regex.exec(str); //["Hello "]

和 (?:) 區(qū)別是:我習(xí)慣的會(huì)把匹配的總結(jié)果叫做總分組,match 函數(shù)返回?cái)?shù)組每一項(xiàng)都是總分組,exec 函數(shù)的返回?cái)?shù)組的第一項(xiàng)是總分組。(?:) 會(huì)把括號(hào)里的內(nèi)容計(jì)入總分組,(?=) 不會(huì)把括號(hào)里的內(nèi)容計(jì)入總分組。

說白了,還是強(qiáng)大的 lastIndex 在起作用。(?:) 和 (?=) 差別是有的,使用的時(shí)候要合適的取舍。

說了這么多關(guān)于 (?=) 的內(nèi)容,下面來點(diǎn)進(jìn)階吧!現(xiàn)在的需求是一串?dāng)?shù)字表示錢 "10000000",但是在國際化的表示方法中,應(yīng)該是隔三位有個(gè)逗號(hào) "10,000,000",給你一串沒有逗號(hào)的,替換成有逗號(hào)的。

var str = "10000000";
var regex = /d(?=(d{3})+$)/g;
str.replace(regex, "$&,"); //"10,000,000"

我們分析一下 regex,/d(?=(d{3})+$)/g 它是全局 g,實(shí)際上它匹配的內(nèi)容只有一個(gè) d,(?=(d{3})+$) 是預(yù)判的內(nèi)容,之前說過,預(yù)判的內(nèi)容不計(jì)入匹配結(jié)果,lastIndex 還是停留在 d 的位置。(?=(d{3})+$) 到結(jié)尾有至少一組 3 個(gè)在一起的數(shù)字,才算預(yù)判成功。

d = 1 的時(shí)候,不滿足預(yù)判,向后移一位,d = 0,滿足預(yù)判,replace。

(?!) 前瞻判斷

(?=) 和 (?!) 叫做正向預(yù)查,但往往是正向這個(gè)詞把我們的思維給束縛住了。正向給人的感覺是只能在正則表達(dá)式后面來預(yù)判,那么預(yù)判為什么不能放在前面呢。下面這個(gè)例子也非常有意思。

一個(gè)簡單密碼的驗(yàn)證,要保證至少包含大寫字母、小寫字母、數(shù)字中的兩種,且長度 8~20。

如果可以寫多個(gè)正則,這個(gè)題目很簡單,思路就是:/^[a-zA-Zd]{8,20}$/ && !(/[a-z]+/) && !(/[A-Z]+/) && !(/d+/),看著眼都花了,好長一串。

下面用 (?!) 前瞻判斷來實(shí)現(xiàn):

var regex = /^(?![a-z]+$)(?![A-Z]+$)(?!d+$)[a-zA-Zd]{8,12}$/;
regex.test("12345678"); //false
regex.test("1234567a"); //true

分析一下,因?yàn)橄?(?!) 預(yù)判不消耗 lastIndex,完全可以放到前面進(jìn)行前瞻。(?![a-z]+$) 的意思就是從當(dāng)前 lastIndex (就是^)開始一直到 $,不能全是小寫字母,(?![A-Z]+$) 不能全是大寫字母,(?!d+$) 不能全是數(shù)字,[a-zA-Zd]{8,12}$ 這個(gè)是主體,判斷到這里的時(shí)候,lastIndex 的位置仍然是 0,這就是 (?!) 前瞻帶來的效率。

對 JS 正則不支持 (?<=) 個(gè)人看法

我們都知道,JS 中的正則表達(dá)式是不支持正回顧后發(fā)斷言的 (?<=),當(dāng)然也不支持 (?。有時(shí)候會(huì)覺得這種正回顧后發(fā)斷言確實(shí)很有幫助,它可以讓我們的思維更清晰,哪些是真正匹配的正則,哪些是斷言的正則。在 Python 中我們就可以輕松的使用 (?<=),但是在 JS 中不行。

原因可能是采用的正則引擎不一樣導(dǎo)致,既然不支持,那我們也只能通過現(xiàn)有的條件來改進(jìn)我們所寫的正則,下面就說一說我的理解。

對于一個(gè)非全局匹配的正則表達(dá)式,完全可以通過 (?:) 來實(shí)現(xiàn)。比如對于 /(?<=Hello) (.*)$/(這個(gè)在 JS 中是不支持的),可以使用 /(?:Hello) (.*)$/作為一個(gè)簡單的替代,這兩個(gè)正則的差別就在于最終的匹配分組上面,總分組略有不同,但總有辦法可以解決。但要注意,這是非全局匹配,反正只匹配一次。

那如果是全局匹配呢?又該如何實(shí)現(xiàn) (?<=)?

var str = "a1b2c3d";
//var regex = /(?<=w)dw/g
//str.match(regex) => ["1b","2c","3d"]
var regex2 = /(?:w)dw/g
str.match(regex2); //["a1b", "c3d"]

很明顯,只通過 (?:) 就顯得有點(diǎn)力不從心了,我們想要的結(jié)果是 ["1b","2c","3d"],卻返回其中的第一和第三個(gè),少了第二個(gè)。

這時(shí)候,又要拿出強(qiáng)大的 lastIndex

var str = "a1b2c3d";
var regex = /(?:w)(dw)/g;
var m,arr = [];
while(m = regex.exec(str)){
  arr.push(m[1]);
  regex.lastIndex --;
}
arr; //["1b", "2c", "3d"]

和前面的例子很類似,通過重寫 lastIndex 的值,達(dá)到模仿 (?<=) 的作用。

非貪婪與貪婪的問題

貪婪出現(xiàn)在 + * {1,} 這種不確定數(shù)量的匹配中,所謂的貪婪,表示正則表達(dá)式在匹配的時(shí)候,盡可能多的匹配符合條件的內(nèi)容。比如 /hello.*world/ 匹配"hello world,nice world"會(huì)匹配到第二個(gè) world 結(jié)束。

鑒于上面的情況,可以使用 ? 來實(shí)現(xiàn)非貪婪匹配。? 在正則表達(dá)式中用途很多,正常情況下,它表示前面那個(gè)字符匹配 0 或 1 次,就是簡化版的 {0,1},如果在一些不確定次數(shù)的限制符后面出現(xiàn),表示非貪婪匹配。/hello.*?world/ 匹配"hello world,nice world" 的結(jié)果是 hello world

我剛開始寫正則的時(shí)候,寫出來的正則都是貪婪模式的,往往得到的結(jié)果和預(yù)想的有些偏差,就是因?yàn)樯倭?? 的原因。

我初入正則的時(shí)候,非貪婪模式還給我一種錯(cuò)覺。還是前面的那個(gè)例子,被匹配的內(nèi)容換一下,用/hello.*?world/ 匹配"hello word,nice world",因?yàn)?word 不等于 world,在第一次嘗試匹配失敗之后,應(yīng)該返回失敗,但結(jié)果卻是成功的,返回的是 "hello word,nice world"

一開始我對于這種情況是不理解的,但仔細(xì)想想也對,這本來就應(yīng)該返回成功。至于如何在第一次嘗試匹配失敗之后,后面就不再繼續(xù)匹配,只能通過優(yōu)化 .*。如果我們把 .*?end 這樣子來看,.* 會(huì)把所有字符都吞進(jìn)去,慢慢吐出最后幾個(gè)字符,和 end 比較,如果是貪婪,吐到第一個(gè)滿足條件的就停止,如果是非貪婪,一直吐到不能吐為止,把離自己最近的結(jié)果返回。

所以,貪婪是返回最近的一次成功匹配,而不是第一次嘗試

避免回溯失控

回溯可以殺死一個(gè)正則表達(dá)式,這一點(diǎn)都不假。關(guān)于正則表達(dá)式回溯也很好理解,就是正則引擎發(fā)現(xiàn)有兩條路可以走時(shí),它會(huì)選擇其中的一條,把另一條路保存以便回溯時(shí)候用。

比如正則 /ab?c/ 在成功匹配到 a 之后,后面可以有 b,也可以沒有 b,這時(shí)候要提供兩種選擇。還有其他類型的回溯,比如 /to(night|do)/。當(dāng)然影響性能的回溯就要和 .* .+ .{m} 有關(guān)。

所謂的回溯失控,就是可供選擇的路徑太多,看一個(gè)常見回溯失控的例子,正則 /(A+A+)+B/ ,如果匹配成功,會(huì)很快返回,那么匹配失敗,非常可怕。比如來匹配 10 個(gè) A AAAAAAAAAA,假設(shè)第一個(gè) A+ 吞了 9 個(gè) A,整個(gè)正則吐出最后一個(gè)字符發(fā)現(xiàn)不是 B,這一輪吐完,還不能返回 false,因?yàn)檫€有其他路可以選擇;第一個(gè) A+ 吞 8 個(gè) A,....一直這樣回溯下去,回溯次數(shù)的復(fù)雜度大概是 2 的 n 次方吧。

當(dāng)然你可能會(huì)說,自己不會(huì)寫這樣傻的正則表達(dá)式。真的嗎?我們來看一個(gè)匹配 html 標(biāo)簽的正則表達(dá)式,/[sS]*?[sS]*?[sS]*?[sS]*?[sS]*? (感覺這樣寫也很傻)。如果一切都 OK,匹配一個(gè)正常的 HTML 頁面,工作良好。但是如果不是以 結(jié)尾,每一個(gè) [sS]*? 就會(huì)擴(kuò)大其范圍,一次一次回溯查找滿足的一個(gè)字符串,這個(gè)時(shí)候可怕的回溯就來了。

在說到回溯的同時(shí),有時(shí)候還是要考慮一下 . * {} 查詢集合的問題,反正我的建議是盡量避免使用匹配任何字符的 [sS],這真的是有點(diǎn)太暴力了。因?yàn)槲覀儗懻齽t的時(shí)候,都是以正確匹配的思路去寫的,同時(shí)還需要考慮如果匹配不成功,該如何盡快的讓 [a-zA-Z]* 集合盡快停止。比如通常在匹配 HTML 標(biāo)簽的時(shí)候正則如果這樣寫 /<([^>]+)>[sS]*?/ (匹配一個(gè)不帶 class 等屬性的標(biāo)簽),匹配成功時(shí),一切都好說,如果匹配失敗,或者匹配的文本中恰好只有左半個(gè) < ,由于范圍 [^>] 范圍太大,根本停不下來,相比來說 /<(w+)>[sS]*?/` 要好一些。又比如 [^ ]* 在匹配單行時(shí)效果不錯(cuò),即時(shí)匹配失敗也可以快速停止。

總結(jié)

感覺這篇文章寫的很亂,東扯西扯的,大概把我這幾個(gè)月以來所學(xué)到的正則表達(dá)式知識(shí)都寫在了這里,當(dāng)然這并不包括一些基礎(chǔ)的知識(shí)。我覺得學(xué)習(xí)正則最主要的還是去練習(xí),只有在實(shí)際項(xiàng)目中總結(jié)出來的正則經(jīng)驗(yàn),才算自己正在掌握的,如果只是簡單的掃一眼,時(shí)間久了,終究會(huì)忘記。共勉!

參考

RegExp對象 - 阮一峰
MSDN RegExp
進(jìn)階正則表達(dá)式

如何找出文件名為 ".js" 的文件,但要過濾掉 ".min.js" 的文件。

代碼如下:

歡迎來我的博客參考代碼。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/80806.html

相關(guān)文章

  • 我所理解正則達(dá)式

    摘要:關(guān)于,新手理解起來可能比較困難,尤其是一些很牛逼的預(yù)查正則表達(dá)式。非貪婪與貪婪的問題貪婪出現(xiàn)在這種不確定數(shù)量的匹配中,所謂的貪婪,表示正則表達(dá)式在匹配的時(shí)候,盡可能多的匹配符合條件的內(nèi)容。 學(xué)習(xí)了半年的正則表達(dá)式,也不能說一直學(xué)習(xí)吧,就是和它一直在打交道,如何用正則表達(dá)式解決自己的問題,并且還要考慮如何在匹配大量的文本時(shí)去優(yōu)化它。慢慢的覺得正則已經(jīng)成為自己的一項(xiàng)技能,逐漸的從一個(gè)正則表...

    K_B_Z 評(píng)論0 收藏0
  • JAVA筆記 - 收藏集 - 掘金

    摘要:動(dòng)態(tài)代理個(gè)經(jīng)紀(jì)人如何代理個(gè)明星掘金在代理模式女朋友這么漂亮,你缺經(jīng)紀(jì)人嗎中我們用寶強(qiáng)的例子介紹了靜態(tài)代理模式的概念。掘金使用從頭創(chuàng)建一個(gè),這種方法比較簡單。 動(dòng)態(tài)代理:1 個(gè)經(jīng)紀(jì)人如何代理 N 個(gè)明星 - Android - 掘金在 代理模式:女朋友這么漂亮,你缺經(jīng)紀(jì)人嗎? 中我們用寶強(qiáng)的例子介紹了靜態(tài)代理模式的概念。 本來我的目的是通過大家耳熟能詳?shù)睦觼砑由罾斫猓怯行┚W(wǎng)友指責(zé)...

    kamushin233 評(píng)論0 收藏0
  • 查漏補(bǔ)缺 - 收藏集 - 掘金

    摘要:醞釀許久之后,筆者準(zhǔn)備接下來撰寫前端面試題系列文章,內(nèi)容涵蓋瀏覽器框架分鐘搞定常用基礎(chǔ)知識(shí)前端掘金基礎(chǔ)智商劃重點(diǎn)在實(shí)際開發(fā)中,已經(jīng)非常普及了。 這道題--致敬各位10年阿里的前端開發(fā) - 掘金很巧合,我在認(rèn)識(shí)了兩位同是10年工作經(jīng)驗(yàn)的阿里前端開發(fā)小伙伴,不但要向前輩學(xué)習(xí),我有時(shí)候還會(huì)選擇另一種方法逗逗他們,拿了網(wǎng)上一道經(jīng)典面試題,可能我連去阿里面試的機(jī)會(huì)都沒有,但是我感受到了一次面試1...

    YuboonaZhang 評(píng)論0 收藏0
  • 基礎(chǔ)知識(shí) - 收藏集 - 掘金

    摘要:本文是面向前端小白的,大手子可以跳過,寫的不好之處多多分鐘搞定常用基礎(chǔ)知識(shí)前端掘金基礎(chǔ)智商劃重點(diǎn)在實(shí)際開發(fā)中,已經(jīng)非常普及了。 JavaScript字符串所有API全解密 - 掘金關(guān)于 我的博客:louis blog SF專欄:路易斯前端深度課 原文鏈接:JavaScript字符串所有API全解密 本文近 6k 字,讀完需 10 分鐘。 字符串作為基本的信息交流的橋梁,幾乎被所有的編程...

    wdzgege 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<