摘要:近幾日對自己一直不太擅長的正則表達式做了一次全面的掃盲。量詞在正則中,通常要表示一個表達式匹配的數量,這個時候量詞就登場了。而正則默認是貪婪模式的。正則會默認對捕獲組分配組數。
近幾日對自己一直不太擅長的正則表達式做了一次全面的掃盲。心疼自己之余還是有一些收獲吧,在這里做一個比較零散的總結,整理一些對理解正則比較有利的點。一、"?"
你沒有看錯,就是黑人問號中的問號,這個字符在正則里面算是一個入門中很容易被帶偏的點了。首先要知道什么是正則中的量詞。
在正則中,通常要表示一個表達式匹配的數量,這個時候量詞就登場了。
主要會使用以下幾個量詞
/(w)*/.exec(str) // 匹配任意次 /(w)+/.exec(str) // 匹配一次到多次 /(w)?/.exec(str) // 匹配零到一次(記住這里問號的用法!) /(w){2, 4}/.exec(str) // 匹配兩次到四次 /(w){2, }/.exec(str) // 匹配兩次以上
我們可以發現,在這里"?"作為一個量詞來使用,表示匹配零到一次。
接下來要理解下一個概念:貪婪匹配
搜了一下wiki,貌似沒有相關的詞條,通俗的解釋,貪婪匹配模式下,會盡可能多地匹配滿足條件的字符。而正則默認是貪婪模式的。
舉個例子。比如我要匹配"suuuuuuuuuuck"字符中的s和k中間的字符。并沒有什么問題。
let result = "suuuuuuuuuuck".match(/s(.*)k/)[1] // uuuuuuuuuuc
但是我現在要搞事情,要你在"suuuuuuuuuuck duck"字符串中匹配相同的字段,同樣的表達式會匹配到以下的結果,因為此時的正則是貪婪的,它一定會匹配到無法匹配的時候才休止。
// uuuuuuuuuuck duc
這時候就需要手動開啟非貪婪模式了
let result = "suuuuuuuuuuck duck".match(/s(.*?)k/)[1] // uuuuuuuuuuc
區別是在量詞后加了個問號,這時候該捕獲組就算是開啟了非貪婪模式了。
按照上面的理解,如果你是一個新手,肯定會有所疑惑,量詞(*)后面跟著一個量詞(?),這是什么鬼意思,這么反人類的?
其實,這里就涉及到"?"的第二個用法了,即當它跟在一個量詞背后的時候,表示該表達式開啟了非貪婪模式,即對表達式盡可能少地匹配結果。所以,對應的,配合量詞使用,會產生以下結果。
"*?": 可以匹配任意多次,但是盡量少匹配。
"+?": 至少必須匹配一次,但是盡量少匹配。
"{m, n}?": 至少必須匹配m次,最多只能匹配n次,但是盡量少匹配。
"{m, }?": 至少必須匹配m次,但是盡量少匹配。
思考題:所以,"??" 應該如何匹配呢?二、捕獲組
正則匹配除了驗證一個字符串是否符合條件外,還可以從中提取我們所需要的信息。比如,我們得到了一個"新中國成立于1949-10-01"的字符串,作為一個愛國人士,我們要把這個年月日提取出來謹記于心。所以我寫了一個正則,獲得的結果如下
這里提取的操作就需要通過小括號進行捕獲。正則會默認對捕獲組分配組數。
"新中國成立于1949-10-01".match(/(d{4})-(d{2})-(d{2})/) // ["1949-10-01", "1949", "10", "01", index: 6, input: "新中國成立于1949-10-01", groups: undefined]
我們也可以忽略某些分組"(?:exp)",這樣正則就不會為為其分配組數。
"新中國成立于1949-10-01".match(/(d{4})-(d{2})-(?:d{2})/) // ["1949-10-01", "1949", "10", index: 6, input: "新中國成立于1949-10-01", groups: undefined]
假如我們有一個疊詞判斷的需求,驗證一個詞語是不是"ABA"格式的,我們可以這么做
// 首先漢字的unicode范圍是u4e00-u9fa5 // 這里我們首先對第一個字符進行了捕獲,組數為1 // 然后我們后面通過"1"的方式去復用捕獲組,這樣就意味著匹配到了相同的字符,也就達到了限制的目的。 /([u4e00-u9fa5])[u4e00-u9fa5]1/.test("是不是") // 當然是true
要記住下標對人類來說還是挺麻煩的,可以說完全沒啥可讀性,當然正則也提供了為分組命名的方式
"新中國成立于1949-10-01".match(/(?d{4})-(? d{2})-(? d{2})/) // 我們可以發現,這時候捕獲組不僅擁有組數,同時groups屬性不為空了。 // ["1949-10-01", "1949", "10", "01", index: 6, input: "新中國成立于1949-10-01", groups: {…}] // 展開groups 是這樣的 // {year: "1949", month: "10", date: "01"} /** 當然命名捕獲組也是可以使用的 */ // (? exp) 命名捕獲組 // k 引用 // 還是疊詞的那個例子 /(? [u4e00-u9fa5])[u4e00-u9fa5]k /.test("是不是")
現在有一個需求,匹配出英文語句"I"m singing while you"re dancing"中所有帶有ing后綴的單詞(不包含ing)。要想拿到danc 和 sing,我們需要用到零寬斷言。三、零寬斷言
零寬斷言用于查找某些內容之前或之后的東西,只指定一個位置,本身并不占據字符,這也是為什么我們稱之為零寬度
對于表達式表示肯定,我們稱之為正向,反之稱之為負向,(注意,這里的正負指的是對條件的肯定和否定,而不是匹配的方向。)
而對于匹配的方向而言,我們有另外一種稱呼,對向后匹配的稱之為預測先行,向前匹配的稱之為回顧后發
所以,對應的四種組合分別是
(?=exp) 零寬度正預測先行斷言(斷言自身出現的位置后面能匹配exp)
(?!exp) 零寬度負預測先行斷言(斷言自身出現的位置后面不能匹配exp)
(?<=exp) 零寬度正回顧后發斷言(斷言自身出現的位置前面能匹配exp)
(?
目前的js引擎對回顧后發斷言的實現還不完全,就我所知在chrome能成功使用,但是在nodejs環境下是不識別的。
現在我們從引言中的例子來實踐一下
"I am singing while you"re dancing".match(/([a-zA-Z]+)(?=ing)/g) // 我們忽略前面不滿足的匹配,直到index = 4時,s為單詞邊界,滿足條件 // 而第一個捕獲組是貪婪的,他會首先匹配到整個singing,然后將掌控權交給(?=ing),singing不滿足匹配 "singinging" // 于是開始回溯到單詞 singin,繼續斷言, 匹配到的下一個字符為"g", 不滿足"singining", 又開始回溯到"singi"... // 直到回溯到"sing"時,斷言后面有一個ing,并且是一個單詞邊界,于是"singing"滿足條件,這時候我們的正則匹配到了第一個結果。 // 由于零寬斷言是不消費字符的,所以我們得到整個表達式匹配的第一個結果是"sing" // 于是引擎以同樣的方式向后面的位置查找,得到了danc // ["sing", "danc"]
我們現在看一下怎么使用負向斷言,假如我們有一個系統,3月25號要進行維護,不能使用了,這時候有用戶要辦理業務,選擇日期的時候我們要過濾3月25日這一天,所以產品經理要你臨時加上一條規則限定。
選擇后日期輸出的格式是"yyyy-mm-dd",這時候我們可以這么寫正則
/(?!2018-03-25)(d{4})-(d{2})-(d{2})/.test("2018-03-11") // true 通過驗證 /(?!2018-03-25)(d{4})-(d{2})-(d{2})/.test("2018-03-25") // false
用(?<=exp) 找出 "beep name=wanglihong abcdefg"
"beep name=wanglihong abcdefg".match(/(?<=name=)(w+)/) // ["wanglihong", "wanglihong", index: 10, input: "beep name=wanglihong abcdefg", groups: undefined]
提取a標簽的屬性的同時,通過(?
var template = "點擊跳轉" template.match(/(w+)=(?摸透了零寬斷言,正則的能力也就算上了一個臺階了,當然還有平衡組這種操作,因為在js不支持,所以就暫時不討論了。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93514.html
摘要:對前端來說,使用的場景不多,但是像微信端的對話系統的表情包,就使用到了一個特定的規則。我是一個前端,工作年了,現在失業,想進入騰訊工作,這是我的聯系方式這個正則雖 我發現有個別字符被這個編輯器給刷掉了,但是灰色區域顯示正常,以灰色區域代碼為準 什么玩意? 在我剛開始學習編程的時候,就聽過正則了,也聽說正則很牛逼,懂正則的更牛逼。但是苦于沒有人指點,也沒有使用正則的場景,自己看教程又懵逼...
摘要:正如我標題所說,簡歷被拒??戳宋液啔v之后說頭條競爭激烈,我背景不夠,點到為止。。三準備面試其實從三月份投遞簡歷開始準備面試到四月份收,也不過個月的時間,但這都是建立在我過去一年的積累啊。 本文是 無精瘋 同學投稿的面試經歷 關注微信公眾號:進擊的java程序員K,即可獲取最新BAT面試資料一份 在此感謝 無精瘋 同學的分享 目錄: 印象中的頭條 面試背景 準備面試 ...
摘要:正如我標題所說,簡歷被拒。看了我簡歷之后說頭條競爭激烈,我背景不夠,點到為止。。三準備面試其實從三月份投遞簡歷開始準備面試到四月份收,也不過個月的時間,但這都是建立在我過去一年的積累啊。 本文是 無精瘋 同學投稿的面試經歷 關注微信公眾號:進擊的java程序員K,即可獲取最新BAT面試資料一份 在此感謝 無精瘋 同學的分享目錄:印象中的頭條面試背景準備面試頭條一面(Java+項目)頭條...
摘要:一般在做前后端分離的時候,前端服務器用的都是,可是公司項目是需要運行在上面的,所以綜合考慮之下用比較好一些,然而這方面的資料不如那么多,所以就想記錄一下這段時間遇到的坑,以防自己以后再遇到的時候忘記了,這樣我可以翻出來看看。 一般在做前后端分離的時候, 前端服務器用的都是nginx,可是公司項目是需要運行在windows server上面的,所以綜合考慮之下用IIS比較好一些,然而這方...
閱讀 1648·2019-08-30 15:55
閱讀 973·2019-08-30 15:44
閱讀 866·2019-08-30 10:48
閱讀 2025·2019-08-29 13:42
閱讀 3179·2019-08-29 11:16
閱讀 1235·2019-08-29 11:09
閱讀 2053·2019-08-26 11:46
閱讀 611·2019-08-26 11:44