iT邦幫忙

2022 iThome 鐵人賽

DAY 20
0
自我挑戰組

寫程式帶給我的無形快樂系列 第 20

吃下 Regular Expressions 翻譯年糕 (位置)

  • 分享至 

  • xImage
  •  

年糕很長,就快要吃完了

Regex 的運作:
從文本的 第一個字元前的位置最後一個字元後的位置
一個一個去和 Pattern 做比對
直到 找到匹配的字元 或是 已經搜尋到最後一個字元 才會停止!


錨點 (Anchors)

利用 ^ $ 符號作為錨點

^: 代表文本的開頭
$: 代表文本的結束

例如:

let str = 'Fake it till you make it';
alert(/^Fake/.test(str)); // true

// Fake 在整段文本的開頭 --> 印出 true

單詞邊界 (Word boundary)

Regex Engine 遇到 \b ,它會檢查目前所在位置是否為單詞邊界

例如:

alert( "Hello, Java!".match(/\bJava\b/) ); // Java
alert( "Hello, JavaScript!".match(/\bJava\b/) ); // null

Hello, Java!這段文本中,只有四個位置是單詞邊界

  1. H
  2. o
  3. J
  4. a 後 (Java 第二個 a)

跳脫特殊字元

Regex 有許多特殊的字元,像是 [ ] { } ( ) \ ^ $ . | ? * +

假設要搜尋的對象是這些特殊字元,需要在前面加上 \

例如:

alert( "Chapter 5.1".match(/\d\.\d/) ); // 5.1 (match!)
alert( "/".match(/\//) ); // '/'

特殊個性的量詞 (Greedy and lazy quantifiers)

貪婪搜尋 (Greedy search)

Regex Engine 對於文本中每一個位置,都會重新去試著匹配所給的pattern,如果沒有,就轉移到下一個位置
Regex Engine 會一個位置一個位置往後推移檢查

例如:

let regexp = /".+"/g;
let str = 'a "witch" and her "broom" is one';
alert( str.match(regexp) ); // "witch" and her "broom"

// ".+" 這個 pattern 中第一個字元是 "
// 檢查到字母 a 不匹配 --> 往後找 --> 空格不匹配 --> 往後找 --> 在位置3的地方找到 "

// 引號找到了,Regex Engine 會接著往文本的後方看,看是否符合 .+
// . 代表任意字元,換行除外,所以 w 字母符合
// 因為有加量詞 + (一次以上),所以後面的字元都符合
// 直到... 文本結束的位置

這樣出現的問題是
.+ 會不斷地去 match 下一個位置的字元,直到文本結束。但都已經到文本的最後,也就不可能找到 "

Regex Engine 知道這點,所以會進行回溯 (倒退一格)
於是 .+ 本來會比對到 one 的 e --> 倒退一個位置,只比對到 n --> e 則讓給 pattern 中的 "
backtrack

e 和 " 不匹配,所以 Regex Engine又再倒退一格
持續回溯倒退,直到找到 " 可匹配

backtrack ending

Regex Engine 預設是採用這樣的貪婪模式,數量越多越好 挑戰極限


懶惰模式 (Lazy mode)

和上述的 Greedy mode 相反,數量盡可能找到越少越好

在量詞後面加上 ? ,就可以啟用 Lazy mode,像是 *? +? ??

例如:

let regexp = /".+?"/g;
let str = 'a "witch" and her "broom" is one';

alert( str.match(regexp) ); // "witch", "broom"

// 一樣在第三個位置找到 "
// 接著試著往後找字元可和 . 匹配

因為使用了 .? 懶惰模式,所以一但找到一個符合 . 的字元,下一個文本位置就會和剩餘的 pattern 進行比對

例如:
pattern " 和文本中的 i 做比對 --> 不匹配 --> i 歸給 . --> 往後一個位置
pattern " 和文本中的 t 做比對 --> 不匹配 --> .... --> 持續往後找

lazy

以上圖皆取自 Greedy and lazy quantifiers


快樂泉源

吸引力法則,每次複習完 Regex 都會在莫名的不久後,相遇它 (?)

: 表單需要驗證各個欄位
: 沒問題

: 這段文字可以幫我只取中間這段嗎
: 沒問題

: 可以幫我看看這段 Regex 寫錯在哪嗎
: 沒問題


上一篇
[雜談] 取名定程式碼的一生
下一篇
吃下 Regular Expressions 翻譯年糕 (環顧四周)
系列文
寫程式帶給我的無形快樂30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言