創造一個正規式
正規式的基本結構通常以/
開頭以/
結尾,來寫個簡單的正規式
1 | var regexp = /xxx/ |
還可以用 JavaScript內建的建構子來創建一個正規式
1 | var regexp = new RegExp('xxx') |
用 tpyeof
來檢驗他的型別是什麼
1 | typeof regexp |
可以發現他是物件,JavaScript很多東西都是物件型別,包含陣列和函式。
使用正規式來檢驗字串 test()
先宣告一組簡單的字串
1 | var str = 'This is a book' |
透過 JavaScript正規式所提供的語法 text
來檢驗字串使否符合我們的正規式
1 | /a/.test(str) // output: true |
因為 str 的這個字串內有 a這個字母,因此輸出為 ture
。
稍微修改一下
1 | /z/.test(str) // output: false |
由於 str 字串內並沒有 z 字母,所以回傳 false
。
使用正規式做字串取代 replace()
我們可以透過 replace()
方法來做正規式篩選,並取代回傳為 true 的字串內容
1 | var str = 'This is a book' |
將字串內的 ‘is’ 用 ‘xx’ 取代
1 | str.replace('is', 'xx') // output: "Thxx is a book" |
有發現什麼地方怪怪的嗎? 為什麼正規式只取代了 this
中的 is
,而忽略的 be動詞 is
呢?
取代多個
剛剛的例子中我們其實並沒有使用到正規式,而是用單純的is 字串做篩選而已,一開始我們就提到,正規式是需要包含 /
開頭結尾的。
來修來一下程式碼
1 | str.replace(/is/, 'xx') // output: "Thxx is a book" |
Wait Wait Wait! What? 不對欸不對欸,換成了正規式,輸出結果還是沒有變?
使用正規式取得特定字串 match()
試著取出 HTML 中 h3 標籤間內的文字
1 | let htmlStr = ` |
透過 match 方法做篩選
1 | htmlStr.match(/<h3>.*?<\/h3>/) |
輸出結果
1 | ["<h3>吳先生</h3>"] |
若要取得標籤內文字, 可以透過 () 進行標註
1 | htmlStr.match(/<h3>(.*?)<\/h3>/) |
結果會將 () 符合條件的文字也推入返回的陣列中
1 | ["<h3>吳先生</h3>", "吳先生"] |
Regex Flags
其實是這樣的,正規式另外有若干的模式可以做設定,常見的三種參數有 i
、g
、m
。
他們分別代表 insensitive
、global
、multi line
。
補充:除了上述三種模式以外,還有另外三種比較進階的,分別是
sticky
、unicode
、single line
,是在 ES6 以後出現的模式。
global
全局匹配
預設模式只會取代字串中第一個符合的對象,後面的會直接忽略。
現在我們使用 g
模式,如此一來檢驗的目標中所有符合的對象都會順利被取代。
1 | str.replace(/is/g, 'xx') // output: "Thxx xx a book" |
insensitive
忽略大小寫
一般來說在使用正規式是有區分大小寫的,我們直接看下面的例子。
1 | var str = 'This is a book' |
結果是沒有任何變化的,因為小寫 this
和大寫 This
是會被判斷為不同的。
修改一下程式碼
1 | var str = 'This is a book' |
加入 i
參數,可以忽略大小寫,如此一來輸出結果就如我們所預期的囉!
multi line
多行匹配
這個比較難以敘述,直接用程式碼來說明吧~
1 | var str = 'iPhone4\niPhone5\niPhone6\niPhone7\niPhone8' |
只要在字串內放入 \n
會產生換行的符號,如果這時候來試試看取代會發生什麼事呢?
1 | str.replace(/iPhone/, 'iPad') |
1 | // output: |
和剛才的情況一樣只取代了第一個符合的目標。
诶? 這不是一樣用剛剛學到的
g
就可以解決了嗎 ?
來試試看吧
1 | str.replace(/iPhone/g, 'iPad') |
1 | // output: |
確實成功了!
不過!在實際的情況下可能還有意外的事情會發生!
1 | str.replace(/^iPhone/g, 'iPad') |
上面的向上箭頭 ^
是一個正規式很常見符號,簡單說明一下它的意義,它會去匹配字串的開頭
。我們來看看 str.replace(/^iPhone/g, 'iPad')
的輸出結果。
1 | // output: |
現在,又只修改到第一個符合的目標了!
怎麼會醬 ?
/^iPhone/
的定義為開頭
符合字串iPhone
的目標,在沒有使用 m
模式的情況下,即使有換行,他們也不會被視為一個新的開頭,可以想像字串就相當於
'iPhone4iPhone5iPhone6iPhone7iPhone8'
這樣的一大串文字,他們的開頭是 iPhone4
中的iPhone
字眼。
現在我們來修改一下程式碼
1 | str.replace(/^iPhone/gm, 'iPad') |
輸出結果
1 | "iPad4 |
常用情境
資料驗證
有沒有經驗是當你在註冊某些網站的服務時,當你輸入 E-mail 格式不包含 @
或是一些 .
時,網站會有格是錯誤提示,這是怎麼做到的呢?
1 | //please input the test email to see is valid |
上網搜尋一下正規式 表單驗證
其實就很容易找到相關的程式碼了。
由於 E-mail 的格式是固定的,為了避免用戶錯誤輸入,將必定驗證不過的E-mail格式傳到資料庫,消耗不必要的資源,通常在前端我們就會透過正規式的技巧來做簡單的篩選。
搜尋功能
相信會看到這篇文章的各位,大部分都有使用文字編輯器。像是筆者使用的文字編輯器是 VS code,我非常常使用到 ctrl + shift + F
的搜尋功能,以往都是使用單純的字串搜尋,但其是現在有非常多的文字編輯器( 或是其他服務 ),都有提供正規式搜尋功能,學會了以後對於資料的篩選精確度會有非常大的提升!
regex101 正規式測試服務
這是一個正規式測式的服務,提供正規式的撰寫測試。
Regex101 Website
設定程式語言
進入網站第一件事情需要先設定程式語言,雖然幾乎所有程式語言都支援正規式,但之中還是有些微差異,有些功能並不是每個程式語言都會支援,但總體來說大概有80%
的語法在所有語言都通用。
因為筆者是Web前端開發者,所以這邊我選 JavaScript。
基本功能說明
常用字元
字面值
如 a b c d 1 2 3 4
等等指定字。
字符類
. [abc] [a-z] \d \w \s
.
表示任何字符
[abc]
括號表示找到集合裡任意一個字符
。\d
表示一個數字
,等同於[0-9]\w
表示一個單詞字符
,等同於[0-9A-Za-z_]\s
表示一個空格,tab,回車或一個換行符
[^abc] \D \W \S
: 否定字符類,和上述同字母小寫的意義相反
乘法器
{4} {3,16} {1,} ? * +
{3,16}
表示找到重複3 到16 次內的字元?
表示”沒有或出現一次”*
表示”沒有或出現多次”+
表示”一個或出現多次”
分支和組合
(Septem|Octo|Novem|Decem)ber
- 符號
|
表示”或” - 圓括號表示組合,比如在一周中找到一天,使用
(Mon|Tues|Wednes|Thurs|Fri|Satur|Sun)day
。
詞、行和文本邊界
^
表示行開始$
表示行結束
反向捕獲組
比如有一段字符,我們需要前面的橫槓去掉,英文句號換成橫槓,尾巴的數字去掉,但是編號
及文章標題
需要保留。
1
2
3
4
5-1.文章標題1
-2.文章標題2
-3.文章標題3
-4.文章標題4
-51.文章標題5
將上文宣告成一組換行字串
1 | var str = '-1.文章標題1\n-2.文章標題2\n-3.文章標題3\n-4.文章標題4\n-51.文章標題5' |
我們預計要將字串替換成 [編號]-[標題]
我們的正規式為 / -
(\d+)
\.
(.+)
\d+
/ g
RegEx | 代表意義 |
---|---|
- |
固定字串 |
★ (\d+) |
至少一位數的數字(編號),小括號內的值之後可以用$1輸出 |
\. |
固定字串,由於dot在正規式是有意義的,須以反斜線標記,代表為固定字串. |
★ (.+) |
至少一個字的任意字元(標題),小括號內的值之後可以用$2輸出 |
\d+ |
至少一位數的數字 |
g |
全局匹配 |
而其中$1
$2
分別代表正規式中小括號內的字串,他們是由左自右排列的,舉例來說若將 (\d+)
的小括號移除,則後面的 (.+)
往前遞補,變成 $1
的參考值,$2
則不存在了。
有時候我們需要括號來作區隔,但是不希望它形成一個群組,意即不希望小括號內的值成為
$
的參考值時,我們可以在小括號的前方加上?:
,就可以把群組取消。如例子中可以將(\d+)
改為(?:\d+)
,這麼一來現在的$1
參考到的值是(.+)
,而$2
則不存在了。
使用replace()
方法替換內容。
1
str.replace(/-(\d+)\.(.+)\d+/g, '$1-$2')
1 | // output: |
空白字元
- 直接打空白鍵 → space
\t
→ TAB\n
→ 換行\r
→ 回車符\s*
→ 所有空白字元
其他
預查
正向預查
(?=)
有時候我們希望匹配的字串符合某個條件,但不希望該條件也被選取反向預查
(?!)
(?=)
&(?!)
和上面補充的(?:)
相同,都不會使小括號內值被群組。
參考資料
[偷米騎巴哥]正規式苦手超入門
Jark’s Blog - 正則表達式學習
正規式語法大全
常見正規式範例 - Email 正規式
常見正規式範例 - 驗證整數和小數的正則表達式