正規表示式對於我來說一直像黑暗魔法一樣的存在。手機正則去網上搜,郵箱正則去網上搜,複雜點的看看文件拼湊一下,再複雜只能厚著臉皮讓其他同事給寫一個。從來沒有系統的學習過,今天準備拿下它。
1. 學習目標:
- 瞭解正規表示式語法
- 在IDE中使用正規表示式
- 在javascript 中使用正規表示式處理字串
2. 什麼是正規表示式
正規表示式,又稱正規表示式、正規表示法、正規表示式、規則表示式、常規表示法(英語:Regular Expression,在程式碼中常簡寫為regex、regexp或RE),電腦科學的一個概念。正規表示式使用單個字串來描述、匹配一系列匹配某個句法規則的字串。在很多文字編輯器裡,正規表示式通常被用來檢索、替換那些匹配某個模式的文字。
通俗的講就是按照某種規則去匹配符合條件的字串
3.利用圖形化工具理解正規表示式
輔助理解正則表達的線上工具 regexper.com/ 我們利用這個工具輔助理解,正規表示式。語法沒懂表著急,後面會有,這裡只是學會用工具幫助我們學習。
手機號正則
/^1[34578][0-9]{9}$/
註釋:以1開頭,第二位為3 4 5 7 9 其中一個,以9位(本身1次加重複8次)0-9數字結尾
單詞邊界
/is/
註釋: is前後都是單詞的邊界,比較晦澀難懂?感受下兩者的區別, 會方道語法部分講解
URL分組替換
/http:(//.+.jpg)/
看不懂的不要慌語法部分後面會有介紹,這裡只是展示利用視覺化的圖形幫助我們理解正規表示式,可以回來再看木有關係
正規表示式中括號用來分組,這個時候我們可以通過用$1
來獲取 group#1的內容
說下這個正則的意義,如果網站用了https,網站引用靜態資源也必須是https,否則報錯。如果寫成 //
會自動識別 http 或者 https
日期匹配與分組替換
/^d{4}[/-]d{2}[/-]d{2}$/
這個正則比較複雜,畫符唸咒的地方太多了,一一分析:
- Start of line 是由
^
生效的表示以此開頭 - 對應結尾End of line 由
$
生效表示以此結尾 - 接著看digit 由
d
生效表示數字 - 3times 由
{4}
生效表示重複4次,開始的時候有疑問,為什麼不是 4times 。後來明白作者的用意,正規表示式是一個規則,用這個規則去從字串開始匹配到結束(注意計算機讀字串可是不會分行的,都是一個串,我們看到的多行,人家會認為是個 - 接下來,是 one of 在手機正則裡面已經出現了。表示什麼都行。只要符合這兩個都讓通過。
好了這個正則解釋完了,接下來用它做什麼呢?
我們可以驗證日期的合法性
結合URL分組替換所用到的分組特性,我們可以輕鬆寫出日期格式化的方法
改造下這個正則
/^(d{4})[/-](d{2})[/-](d{2})$/
輕鬆的可以拿到 group#1 #2 #3 的內容,對應 $1
$2
$3
到現在已經能結合圖形化工具看懂正規表示式表示式了,如果想自己寫,還要在正則語法上下點功夫
4. Js中Regexp物件
Javascript 通過內建物件RegExp支援正規表示式,有兩種方法例項化RegExp物件
字面量方法
const reg =/is/g
建構函式
const reg = new RegExp(`\bis\b`, `g`)
注意:第一個引數為正規表示式字串(注意轉譯),第二個引數為修飾符,修飾符g代表全域性搜尋,後面會有詳細介紹。
5. 正規表示式語法
1 修飾符 (三個 g i m)
修飾符與其他語法特殊,字面量方法聲名的時候放到//
後,建構函式宣告的時候,作為第二個引數傳入。整個正規表示式可以理解為正規表示式規則字串+修飾符
- g:global 執行一個全域性匹配
- i:ignore case執行一個不區分大小寫的匹配
- m: multiple lines多行匹配
修飾符可以一起用 const reg =/is/gim
來說說他們有什麼作用
有g和沒有g的區別
沒有g只替換了第一個,有g 所有的都換了
有i和沒有i的區別
有i忽略大小寫,沒有i嚴格區分大小寫
2 元字元
正規表示式由兩種基本字元組成:
- 原義字元
- 非列印字元
- 元字元 (* + ? $ ^ . | ( ) { } [ ])
3. 原義字元
這個沒什麼好解釋的,我們一直在舉例的 /is/ 匹配字串`is`
將下一個字元標記為一個特殊字元、或一個原義字元、或一個向後引用、或一個八進位制轉義符。例如,
n
”匹配字元“n
”。“
”匹配一個換行符。序列“
\
”匹配“”而“
(
”則匹配“(
”。
4. 非列印字元
字元 | 描述 |
---|---|
cx |
匹配由x指明的控制字元。例如, cM 匹配一個 Control-M 或回車符。x 的值必須為 A-Z 或 a-z 之一。否則,將 c 視為一個原義的 `c` 字元。 |
f |
匹配一個換頁符。等價於 x0c 和 cL。 |
|
匹配一個換行符。等價於 x0a 和 cJ。 |
|
匹配一個回車符。等價於 x0d 和 cM。 |
s |
匹配任何空白字元,包括空格、製表符、換頁符等等。等價於 [ f
v]。 |
S |
匹配任何非空白字元。等價於 [^ f
v]。 |
|
匹配一個製表符。等價於 x09 和 cI。 |
v |
匹配一個垂直製表符。等價於 x0b 和 cK。 |
非列印字元,以
為例
其他的在前端引用比較少,應該在後端處理文字檔案的時候會用到
5. 字元類 []
在前面的手機號正則例子?中,我們已經使用過[] /^1[34578][0-9]{9}$/
: [34578]
表示34578任意一個數字即可。在日期匹配與分組替換例子?中 /^d{4}[/-]d{2}[/-]d{2}$/
表示符合 /
-
都可以
6. 字元類取反 [^]
表示不屬於此類
空格也不屬於,好多狗?
7. 範圍類[-]
正規表示式支援一定範圍規則比如 [a-z]
[A-Z]
[0-9]
可以連寫[a-z0-9] 如果你只是想匹配-
在 範圍類最後加-
即可。請看例項。
8. 預定義類
常用為了方便書寫
字元 | 等價類 | 含義 |
---|---|---|
. |
[^
|
除了回車符和換行符之外的所有字元 |
d |
[0-9] |
數字字元 |
D |
[^0-9] |
非數字字元 |
s |
[ |
空白符 |
S |
[^ |
非空白符 |
w |
[a-zA-Z_0-9] |
單詞字元(字母、數字、下劃線) |
W |
[^a-zA-Z_0-9] |
非單詞字元 |
有了這些預定義類,寫一些正則就很方便了,比如我們希望匹配一個 ab+數字+任意字元 的字串,就可以這樣寫了 /abd./
9. 邊界
字元 | 含義 |
---|---|
^ |
以xx開頭 |
$ |
以xx結尾 |
|
單詞邊界,指[a-zA-Z_0-9]之外的字元 |
B |
非單詞邊界 |
邊界顧名思義即定義匹配的邊界條件,上面基本都在前面的例子碰到了,這裡演示下與
B
的區別
10. 量詞
字元 | 含義 |
---|---|
? | 出現零次或一次 |
* | 出現零次或多次(任意次) |
+ | 出現一次或多次(至道一次) |
{n} | 對應零次或者n次 |
{n,m} | 至少出現n次但不超過m次 |
{n,} | 至少出現n次(+的升級版) |
{0,n} | 至多出現n次(其實就是{n,m} 方便記憶而已) |
如果沒有量詞,要匹配4位數字這樣寫就可以/dddd/
, 如果匹配50位100位呢?那不是要瘋掉了?
有了量詞,就可以這樣寫/d{100}/
, 量詞的使用我們在手機號中使用過,表現在視覺化中就是迴圈多少次。
湊一個上面都包含的例項/d?@d*@d+@d{10}@d{10,20}@d{10,}@d{0,10}/
11.貪婪與懶惰(非貪婪)
正規表示式預設會匹配貪婪模式,什麼是貪婪模式呢?如其名儘可能多的匹配。我們看個例子?。
/d{3,6}/
貪婪模式下,匹配的了最多的情況。
與貪婪對應就是懶惰模式,懶惰對應的就是匹配的儘可能少的情況。如何開啟懶惰模式? 在量詞後面加?
。繼續上面的例子
/d{3,6}?/
如果想知道,正規表示式是如何匹配量詞的,請看 進階正規表示式 文中有介紹,正則是如何回溯的。
12.分組與反向引用
分組,又稱為子表示式。把正規表示式拆分成小表示式。概念枯燥,說個例子為嘛用分組:
不分組 /abc{2}/
量詞僅作用到最後的c
分組 /(abc){2}/
注意這裡 group #1
分組雖然和運算子()
很像,但是分組在正規表示式中,注意理解組的含義。經常有人濫用分組
/^(http|https)/
真的需要這樣麼?其實 /^https?/
就可以了,你正則寫的特別長的時候,會出現一堆沒用的結果,看著都頭疼吧。
分組往往和反向引用一起使用,別被概念嚇到:當一個正規表示式被分組後,每個分組自動被賦予一個組號,一左到右分別是 $1
$2
…
再把之前的例子拿出來
/^(d{4})[/-](d{2})[/-](d{2})$/
輕鬆的可以拿到 group#1 #2 #3 的內容,對應 $1
$2
$3
如果在反向引用中不想捕獲年該如何操作? 加上 ?:
即可
/^(?:d{4})[/-](d{2})[/-](d{2})$/
12.前瞻
⚠️ 這部分為進階部分—選看
正規表示式中有前瞻(Lookahead)和後顧(Lookbehind)的概念,這兩個術語非常形象的描述了正則引擎的匹配行為。需要注意一點,正規表示式中的前和後和我們一般理解的前後有點不同。一段文字,我們一般習慣把文字開頭的方向稱作“前面”,文字末尾方向稱為“後面”。但是對於正規表示式引擎來說,因為它是從文字頭部向尾部開始解析的(可以通過正則選項控制解析方向),因此對於文字尾部方向,稱為“前”,因為這個時候,正則引擎還沒走到那塊,而對文字頭部方向,則稱為“後”,因為正則引擎已經走過了那一塊地方。
⚠️注意:後顧效能損耗比較大,js只支援前瞻(知乎上看到的,具體原因不詳)
上面的比較概念話,嘗試用大白話講講,就說皇上選妃吧,先行條件得是美女吧,長得“如花”那樣皇上可不要,漂亮這關過了,皇上想要這個美女也不行,皇室有規矩,必須是貴族血統。
那麼“漂亮”就是正常的匹配,匹配到了,還得看看家室是不是貴族。”貴族”相當於前瞻條件
前瞻分兩種一種是正向前瞻(?=xxx)
, 另一種是負向前瞻(?!xxx)
? 是不是很簡單?那我們來玩個好玩的。
題目:如何將`123456`轉成貨幣帶逗號的。`123,456`。這個是很常規格式化金額的需求。
如果在沒有學習正則之前,我的思路是:
- 字串轉陣列
- 反轉陣列
- 每隔三個新增個逗號
- 新增完了反轉陣列
- 陣列轉字串
好累~~~
今天學習了正則,可以一步到位 `123456789`.replace(/(d)(?=(?:d{3})+$)/g, `$1,`)
到此為止正則的基本使用已經結束,後面一篇會分享一些正則的 「奇技淫巧」