###### tags: `工具` # regex \w 英文、數字或底線 \d 任一數字 \D 任一不是數字 \s 空白 . 換行符號外任一字元 判斷一個字元多種規則[規則規則規則] 量詞放在字的後面 {} ? 0 或 1 次 \+ 1 次或以上 \* 0 次或以上 () 捕獲的字串Capture Groups ![](https://i.imgur.com/dzxQMyx.png) ![](https://i.imgur.com/q52DMjr.png) regex物件中*test*或是*exec*來測試 string物件中*search* *match* *replace* *split* ```javascript const string = "hello World String" const regex =/hello world/i console.log( regex.test(string),//true regex.exec(string),//['hello world',index: 0.....] string.search(regex),//0 string.match(regex),//['hello world',index: 0.....] string.replace(regex,","),//, String string.split(regex),//[ '', ' String' ] ) ``` test跟exec是以regex為主來測試字串是否符合規則,test只回傳布林,exec回傳詳細陣列 search 跟test相反 主角是字串來測regex match 則跟exce相反 也是字串來測regex ## 特殊字元 - ^ 字串的開頭 - $ 字串的結尾 - | 表示or(前後都可以) - \ 使用特殊字元 用\來跳脫字元 特殊字元用法 假如我要找第一個為a開頭中間有 | 或者 * 且最後是9的 a123|4569 ``` const regex = /^a.*\|.*9$/ const string = "a123|4569" console.log(regex.exec(string)) console.log(string.match(regex)) ``` ## 集合[ ] 一堆規則來限制你~~ ```javascript const regex = /[A-Za-z0-9]/ //所有英文及數字 //常用集合有快速的字元喔~ const regex = /./ // 比對換行符號外的任意一個字元 const regex = /\d/ // 比對一個數字,相等於 /[0-9]/ const regex = /\w/ // 比對一個英文、數字或底線,相等於 /[A-Za-z0-9_]/ const regex = /\s/ // 比對一個的空格 (ex: space, tab, 換行, ...) //還有排除法~用[^] //例如 const regex =/[^\d]/ //比對不是數字的 ``` 集合 在一個位置裡如果有多個規則要比較就可以用[]包起來 在這邊有很多快捷可以用~點sdw ## 量詞 連續比對的時候~還有快捷可以用 ``` javascript //我要比對五個數字!! const regex = /\d\d\d\d\d/ //等同於 const regex = /\d{5}/ // 使用 {2,} 表示連續出現 2 次以上 //表示連續出現兩次以上的數字或英文字 const regex = /\w\+{2,}/ // 使用 {2, 5} 表示連續出現 2 ~ 5 次 const regex = /\w\+{2,5}/ // 使用 ? 表示出現 0 或 1 次,等同於 {0,1} const regex = /\w?/ // 使用 + 表示出現 1 次或以上,等同於 {1,} const regex = /\w+/ // 使用 * 表示出現 0 次或以上,等同於 {0,} const regex = /\w*/ !!!如果在量詞後面加一個問號!!! 連續次數出現越少的會優先 ``` 跟集合有點相反,如果要連續的位置比對同一個規則 則可以用{}顯示要比較的次數,或者有? + * 快捷 ## 群組( ) ```javascript // 在使用 exec、match 等方法時,回傳的結果會有以下這些資訊 // [比對成功的字串, 捕獲的字串1, 捕獲的字串2, ..., 字串的起始位置, 命名的捕獲群組] const regex = /user: (\w+)/ regex.exec('user: Alan') // ["user: Alan", "Alan", index: 0, ...] // 每一個 Group 會 '由左至右,由外而內' 的被賦予編號,並被放在執行結果相應的 index 中 // 假設 regex = /((A)(B))/ ,那麼群組就分別是 1:(AB), 2:(A), 3:(B) const regex = /fullName: ((\w+) (\w+))/ regex.exec('fullName: Alan Hsu') // ["fullName: Alan Hsu", "Alan Hsu", "Alan", "Hsu", ...] ``` ### 命名群組 (裡面加?<命名>) ```javascript // 假設要抓出使用者的 firstName 與 lastName const regex = /fullName: (?<firstName>\w+) (?<lastName>\w+)/ regex.exec('fullName: Alan Hsu') // [..., groups: {firstName: "Alan", lastName: "Hsu"}] ``` 群組 要一段裡面判斷不同區塊可以用群組包一塊規則 ## 斷言 在正規表達式中,斷言可以用來指定字串中的某個錨點要符合一些條件,例如前面介紹的特殊字元 `在字串開頭 ^`、`在字串的結尾 $` 就是被歸類在斷言的用法中,常見的斷言還有 `文字邊界 \b` 與 `環顧 Lookaround` 。 ```javascript // 假設要找出 'Java' 而不是 'Javascript' const str = 'difference between Javascript and Java.' // 不使用斷言會找到 'Javascript' 的 'Java' str.match(/Java/) // ["Java", index: 19, ...] // 改使用文字邊界 \b 來比對,就能找到想要的結果了 str.match(/\bJava\b/) // ["Java", index: 34, ...] // 文字邊界指的是在比對到 \b 的位置時,前後相鄰的字元必須有一個不是文字 // 使用 replace 把 \b 替換成 '|' 來看看它的效果 const regex = /\b/g str.replace(regex, '|') // "|difference| |between| |Javascript| |and| |Java|." ``` 字串與錨點的描述,建議到 regex101 實際操作一下,配合網站的視覺效果可以更好的理解它,如果想要判斷的是更複雜的條件,可以使用 `環顧 Lookaround` 。 ```javascript // Lookaround 分為兩種 `Lookahead` 以及 `Lookbehind`,各自又有 positive 與 negative 兩種判斷方式 // Positive Lookahead: A(?=B) → A 後方的條件要符合 B // Negative Lookahead: A(?!B) → A 後方的條件不能符合 B // Positive Lookbehind: (?<=A)B → B 前方的條件要符合 A // Negative Lookbehind: (?<!A)B → B 前方的條件不能符合 A // 假設要取出商品的金額 const str = '數量 2,實付金額 990元' // 分析一下要擷取的資料 "前方有一個空格 + 金額 + 後方有一個'元'" // 把規則寫成正規表達式 const regex = /(?<=\s)\d+(?=元)/ str.match(regex) // ["990", index: 10, ...] ``` 要注意的是,斷言與群組的語法雖然很像,但是斷言的條件不會出現在比對的結果中,所以在正規表達式中也被稱為 Zero-Length Assertions。 斷言跟群組有點像,不過斷言主要用來判斷邊界的情況,以及前後關係 ### ### 1 使用正規表達式來轉換日期。 ```javascript // 將日期 '2020/07/15' 轉換為 '2020年07月15日' const date = '2020/07/15' // 使用 group 把年、月、日抽取出來 const regex = /(\d{4})\/(\d{2})\/(\d{2})/ // 使用 replace + backreference 轉換字串 // 在 replace 中是使用 $1、$2、... 替代群組捕獲的文字 date.replace(regex,'$1年$2月$3日') // "2020年07月15日" // 使用命名群組讓程式碼更好讀 // 在 replace 中是使用 $<name> 替代命名群組捕獲的文字 const regex = /(?<year>\d{4})\/(?<month>\d{2})\/(?<day>\d{2})/ date.replace(regex,'$<year>年$<month>月$<day>日') // "2020年07月15日" ``` ### 2 使用正規表達式幫數字加上三位一撇 (separator)。 其實可以直接用 toLocaleString( ) ```javascript const number = 123456789 // 123,456,789 // 分析一下條件,從個位數開始數,每三位數加上一個',' // 使用非文字邊界 \B 與 Lookahead 來撰寫條件,判斷右邊每 3 個數字為錨點 const regex = /\B(?=(?:\d{3})+)/g number.toString().replace(regex, ',') // "1,2,3,4,5,6,789" // 發現結果不如預期,從數字 5 開始往右數三個數字也符合條件 // 在 Lookahead 裡再加上一個 Negative Lookahead // 判斷每湊滿 3、6、9、... 個數字之後,右邊不能再有其他數字 const regex = /\B(?=(?:\d{3})+(?!\d))/g number.toString().replace(regex, ',') // "123,456,789" ``` ### 3 使用正規表達式限制使用者只能輸入英文與數字 ```javascript // 分析一下條件,每個字元都只能是英文與數字 // 反過來說就是要 trim 掉不是英文與數字的字元 const value = e.target.value this.value = value.replace(/[^A-Za-z0-9]/g, '') ``` [練習](https://regexone.com/)