iT邦幫忙

3

JavaScript - 想請教這段正規表達式的程式碼的意思

小弟自己上網找了用正規表達式和 replace() 處理千位分隔符的問題,但找到的寫法有點看不懂~

我知道 \B 可以比對非英文字的邊界,自己嘗試著把 \B 拿掉,則原本的 10000 和 -10000 會呈現 ,100,000 和 -,100,000 的結果。重新加入 \B 後最前面就沒逗號 , 了,這個背後原理是什麼啊??請大大解釋一下了,感謝~~
/images/emoticon/emoticon41.gif

function change(num) {
  // \B: 比對非英文的邊界
  // ?=(\d{3}): 取出3位數字出來
  // +(?!\d): 該3位數字後面接著非數字的字元

  return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

console.log(change(0));
console.log(change(1234567.90));
console.log(change(-1234567.90));
console.log(change(100000));
console.log(change(-100000));
console.log(change(1234567.9876531));

codepen: https://codepen.io/a90100/pen/pooWxXJ?editors=0011

5
浩瀚星空
iT邦大師 1 級 ‧ 2019-10-31 23:13:36
最佳解答

\B 就是 non-word boundary

由於你的正則內是字位位數來產生空值插入[,]。
但如果開頭剛剛好也是在計算位置的情況。也是會出現,。
這其實並不是我們想要的。

所以\B就會達到分隔處理的效果。
用比較白話點的就是告訴正則。開頭位元不需要處理,就算符合的情況下。
它只是盡了區分的責任。

2
舜~
iT邦好手 1 級 ‧ 2019-11-01 07:53:20

推間一個網站給您學習,我是這網站入門regex的
正则表达式30分钟入门教程

表3.常用的反义代码

代码/语法 说明
\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符

想要練習的話可以在這裡線上測試您的regex
https://regexr.com/

3
fysh711426
iT邦研究生 2 級 ‧ 2019-11-01 17:48:47

我說說我的理解,但不一定正確。

首先將正規式拆成四個部分

\B
(\d{3})+
(?!\d)
(?=...)

\B

\b 是比對一個詞的邊界,而 \B 是反義,代表不是一個詞的邊界
這裡的詞是指連續的 英文數字_

-10000 會被拆成兩個詞 -10000
而 \B 代表不匹配詞邊界,所以開頭的 - 和 1 才沒有被匹配

(\d{3})+

\d 代表匹配數字
{3} 代表 3 個數字
()+ 代表裡面的內容可以符合 1~N 次

這裡比較好理解,就是3個數字分一組

(?!\d)

(?!) 和最外面的 (?=) 中文翻譯是斷言
不過從字面上很難看出它的用途,哈哈哈

(?!) 是不匹配的意思
xxx(?!\d): xxx 後面不能是數字的意思

(?=)

這個是後面必須符合但不能匹配的意思
xxx(?=bbb): xxx 後面必須符合 bbb 的規則,但不把 bbb 匹配進去
有點難懂,舉例 xxxbbb
bbb 雖然被匹配,但結果只會取得 xxx

合起來看

最後合起來的比對方式和我開始想的不太一樣,還蠻有趣的

https://ithelp.ithome.com.tw/upload/images/20191101/20106865lgaPdeqn1Q.jpg

雖然比對是由前往後,但由後往前看會比較清楚

因為要符合 (?!\d) 這個條件
所以可以先將 1234567.9876531 拆成 1234567. 和 9876531
接著因為從 1 開始沒辦法分成 3個3個一組,所以比對失敗
往下一位 2 去比,這時候比對成功
但因為 (?=) 不匹配的關係,只會取 \B 出來 (圖中第一條紫色線)

雖然 234567 已經被比對了,但因為 (?=) 的關係
所以正規式還是可以回頭繼續比對 567 (圖中第二條紫色線)
這裡我覺得是這個正規式精妙的地方

因為正常的比對,比過的地方就不能回頭
這邊利用了 (?=) 不匹配的特性
使正規式還可以回頭,繼續找後面的數字

這是小弟的理解,如果有錯誤再請各位大大指正。

harry xie iT邦新手 5 級 ‧ 2019-11-01 23:06:58 檢舉

好詳細的回覆啊~這樣我就比較了解整段程式碼的意思了,非常感謝~
可惜最佳解答只能一個...不然想把你寫的東西設定為最佳解答啊哈哈
/images/emoticon/emoticon12.gif

harry xie iT邦新手 5 級 ‧ 2019-11-02 00:30:38 檢舉
  • \d{3} 匹配3個數字,+表示前面的内容重複1到多次,所以 (\d{3})+ 表示三個數字的1到多次,也就是3,6,9...等3的倍數個數字的字串
  • (?!\d) 匹配一个位置,此位置後面不是數字
  • (?=(\d{3})+(?!\d)) 匹配一个位置,這個位置後面首先是3的倍數個數字的字串,接下来的位置不是數字
  • /\B(?=(\d{3})+(?!\d))/g 就是全部匹配一个位置,這個位置前面要有字元存在,然後後面是3的倍數個數字,再後面是非數字。

以上,是我個人整理出來的最終理解,都可以討論看看喔~

fysh711426 iT邦研究生 2 級 ‧ 2019-11-02 08:58:28 檢舉

/\B(?=(\d{3})+(?!\d))/g 就是全部匹配一个位置,這個位置前面要有字元存在,然後後面是3的倍數個數字,再後面是非數字。

是這個意思沒錯!
你這樣一步一步的拆解說明很清楚,哈哈哈。

我要發表回答

立即登入回答