正則表達式簡明教程

說明:本文是我在公司技術講座上某次分享的總結。git

正則是字符串匹配模式,在處理文本時頗有用。最多見的操做就是用於查找和替換。編輯器

說處處理文本,其實咱們天天敲的代碼就是文本,所以經常使用的代碼編輯器的查找替換工具基本都支持正則語法的。工具

vscode編輯器查找替換工具

先說明一下,接下來的內容都以《We will rock you》的歌詞測試文本。post

點擊展開歌詞
Buddy, you're a boy make a big noise
Playing in the streets gonna be a big man someday
You got mud on your face
You big disgrace
Kicking your can all over the place
Singing
We will, we will rock you
We will, we will rock you
Buddy you're a young man, hard man
Shouting in the street gonna take on the world someday
You got blood on your face
You big disgrace
Waving your banner all over the place
We will, we will rock you

使用的正則測試工具是 Regex 101學習

這裏建議讀者看的過程當中,同時打開該網站,把歌詞貼進去,每一個案例都驗證一遍。也建議稍微改動一下正則,看看匹配結果還是否與本身的理解一致。跟着動手,學習效果要好一些。測試

1. 精確匹配

正則是用來描述字符串的一種模式(pattern),或者說規律。最平凡的用法,就是精確查找。好比我要找到歌詞中的全部「the」。正則寫成 the 便可。網站

上圖只找到了一個 the,而不是全部的。這是由於正則自己是分兩部分的,一部分是模式,另外一部分是修飾符(flags,或者叫標誌位)。一個經常使用的修飾符是 g,它單詞 global 的簡寫,表示全局查找。spa

此時,咱們找到了全部「the」。接着咱們再找全部「we」。3d

然而,同時咱們也但願找到文本中「We」,w 字符是大寫的。此時能夠用另外常見的標識符 i,單詞 ignoreCase 或者 insensitive 的首字母,表示忽略大小寫。調試

不管 the 或 we,這種模式匹配都是精確匹配,若是正則只是輸入什麼就查找什麼,那麼其存在的意義就沒有那麼大。而它的強大之處在於能實現模糊匹配。

2. 橫向模糊匹配

好比咱們想找到歌詞中全部連續出現的「e」。

圖中正則形如 p{m,n},表示 p 至少連續出現 m 到 n 次(包括m、n)。p 能夠是一個子模式,不必定只是一個字符。

上圖中,爲了測試我修改了部分歌詞。其中正則使用了括號,括號如你所料同樣,起到了高優先級的做用。表示 noise 這個總體重複出現了 1 到 3 次。

不知道此時你是否有疑問,{1,3} 表示 1 到 3 次。爲啥上面的匹配結果只有一個呢?而不是匹配到 3 個 noise。又或者 noisenoise 和 noise,這兩個結果呢?

這是由於量詞有貪婪和惰性之分。{1,3} 這個量詞是貪婪的,能知足條件的話,它會盡量多地匹配。能夠在量詞的後面加個問號,讓其變爲惰性的。

確實夠懶得的,找到一個就知足了。量詞後面的這個問號,似乎是在問量詞,「能夠別再貪了嗎?」

量詞的含義清楚了,下來咱們來看一些簡寫形式。

  • * 等價於{0,}。即任意多個。
  • + 等價於{1,}。即至少一個
  • ? 等價於{0,1}。即有一個或者沒有
  • {m} 等價於{m,m}

這裏要說明的是 ? 這時就可能兩個含義。即一個表示惰性模式,一個表示量詞。

其實兩者很好區分,在量詞以後的 ? 才表示惰性匹配。好比正則 bo??y,第一個問號表示量詞 {0,1},第二個表示量詞是惰性的。

量詞的存在,能讓正則能夠模糊匹配,即不多的模式代碼就能匹配一長串。我稱之爲橫向模糊匹配。還有一種縱向的模糊匹配。

3. 縱向模糊匹配

假設歌詞中有幾處不當心把「rock」寫成「ruck」。咱們須要找到兩者,可使用字符集 r[ou]ck。效果以下:

其中 [ou],這種方括號括起來的模式就是字符集。它是一個集合,匹配「o」或者「u」。又好比咱們要找到全部 a 到 e 的字符,能夠寫成 [abcde]。這種連續的字符也能夠簡寫成 [a-e]。

字符集是集合的意思,而集合有補集。正則裏在方括號內開頭加上脫字符,來表示取反[^a-e],匹配一個不是 a、b、c、d、e 的某字符。

字符類的含義搞清楚了,下來咱們來看一下常見的簡寫形式

  • \d 等價於 [0-9]。表示是一位數字。digit 的首字母。
  • \D 等價於 [^0-9]。
  • \w 等價於 [0-9a-zA-Z_]。表示數字、大小寫字母和下劃線。word的首字母,也稱單詞字符。
  • \W 等價於 [^0-9a-zA-Z_]。
  • \s 等價於 [ \t\v\n\r\f]。表示空白符,包括空格、水平製表符、垂直製表符、換行符、回車符、換頁符。記憶方式:s是space character的首字母。
  • \S 等價於 [^ \t\v\n\r\f]。
  • . 等價於[^\n\r\u2028\u2029]。點是通配符,表示幾乎任意字符。

字符集是正則實現模糊匹配的另一種方式,具體到某一位上,要匹配的字符能夠是不肯定的,我稱之爲縱向模糊匹配。

量詞和字符組掌握了話,基本上正則問題能解決一多半。這裏再舉一個例子。找到全部以「ing」結尾的單詞。

上面使用的是貪婪量詞,若是使用惰性量詞的話,情形會有所不一樣。

此時,「singing」這個單詞分紅了「sing」和「ing」。要完整的匹配一個單詞。須要匹配位置。

4. 匹配一個具體位置

好比匹配「you」這個單詞,可能會匹配到「your」中的 you。

此時咱們可使用\b。b 是單詞 boundary 的首字母。它表示匹配一個位置,這個位置某一邊是\w,另外一邊是\W。也就是一邊是單詞字符,一邊是非單詞字符,所以它叫單詞邊界。

若是對「位置」這一律念,理解得仍是不太透徹,咱們能夠具體看看 \b 到底長什麼樣。

注意上圖中得粉色虛線。它們就是一個個位置。請看看每個是否是兩邊一個是單詞字符,另外一個是非單詞字符。

位置也是有反義的。好比 \B 表示非單詞邊界。咱們也能夠看看。

有了單詞字符後,要準確的匹配單詞「you」,可使用\byou\b。

除了單詞邊界這種位置以外,估計你們應該知道 ^ 和 $。它匹配整個文本的開頭和結尾。

還記得前面咱們找「we」嗎,若是咱們想找到全部行開頭的 we 單詞。咱們可使用多行模式:

此時修飾符裏多了一個 m,是 multiline 的首字母,表示多行匹配。所謂多行匹配,就是說 ^ 和 $,能夠匹配行開頭和行結尾,再也不侷限於整個文本的開頭和結尾。

除了 \b、\B、^、$ 外,還有一種斷言位置。好比 (?=p),表示模式 p 前面的位置。

(?!p)是其反義。還有反向的斷言,例如 (?<=p),表示模式 p 後面的位置。或者說該位置的後面是 p。它也有反義的形式 (?<!p)。請讀者本身嘗試看看都匹配了啥。

關於位置這一起,多說幾句。假如我想找到這樣的位置,該位置不能是開頭,而且後面的字符是 s,此時該怎麼作呢?

(?!^) 其實就是 ^ 的反義。連續寫多個位置是沒有關係的。好比寫 ^^^^。

須要注意的位置不一樣於字符,是不佔地方的,若是說是字符也能夠,它則是空字符,沒有實際寬度的。

正則要麼匹配字符,要麼匹配位置。主體內容介紹完了,接下來查缺補漏。

5. 引用

street 裏有兩個 e,而 all 裏有連個 l。此時我想找到全部這樣的雙棒字母,該怎麼作呢?直接使用 .{2} 是不行的。由於它就是 .. 的簡寫形式,表示兩個任意字符。並無要求這兩個字符相同。

此時,就涉及到了反向引用。參考以下寫法:

\1 是反向引用,表示第一個括號裏捕獲的數據。那麼 \2 呢,表示第二個括號捕獲的。

須要注意一點是這裏的括號,是日常的括號,而不是像 (?=p) 那樣特殊語法的括號。

括號捕獲的數據,不只能夠在正則裏反向引用。也能夠配合宿主 API 來使用,外部引用。好比實現濾重:

上面使用了替換,工具內部必然要用到宿主語言相關 API。$1 表示外部引用第一個分組捕獲的內容。

括號能夠用來提供分組功能,又能捕獲數據。可否只讓括號充當分組功能呢?此時要使用非捕獲分組(?:p),而不是(p)。

6. 分支結構

好比我想找到全部的 face 和 place。此時該怎麼辦?

管道符 |,表示或的關係,多選一。它從左到右面一個個嘗試,若是成功,就再也不繼續嘗試了。能夠說它是短路的、惰性的。好比用 you|your 去匹配 your 時,它只會匹配到 your 的前 3 個字母。因此分支順序不一樣結果可能也會不一樣。

總結

本文,經過案例的形式覆蓋了正則經常使用語法。包括:

  • 量詞
  • 字符集
  • 分支結構
  • 修飾符
  • 位置
  • 引用
  • 常見簡寫

若是文中每一個例子,你都本身手動輸入調試並理解的話,你能夠放心地說本身正則已經入門了。

若是想更全面深刻理解JS正則的話,歡迎閱讀本人的 《JS正則迷你書》

固然,只掌握語法是確定不夠的,還須要大量的練習。

有一個燒水理論,若是歷來沒把水燒開過,無論燒幾回,水都是不能喝的。可一旦燒開過,哪怕放一陣子也是能夠喝的。

初學又不用,很容易忘,就是這個道理。

一個很好練習的地方是 codewars,沒事多刷刷正則相關題目,用不上幾天就熟悉了。

但願有所幫助。

本文完。

相關文章
相關標籤/搜索