###### tags: `工具`
# regex
\w 英文、數字或底線
\d 任一數字
\D 任一不是數字
\s 空白
. 換行符號外任一字元
判斷一個字元多種規則[規則規則規則]
量詞放在字的後面
{}
? 0 或 1 次
\+ 1 次或以上
\* 0 次或以上
()
捕獲的字串Capture Groups


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/)