直接上例子:每三個數字中間加逗號
"123456789".replace(/(\d{3})(?:[^$])/g, ","); //"123,567,9" "123456789".replace(/(\d{3})(?=[^$])/g, ","); //"123,456,789"
再上一個之前論壇裡出現過的例子,也是每三個數字中間加逗號
先看看 (?=pattern) 的使用,下面这个是正确的: function groupByCommas(n) { return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } console.log(groupByCommas(1234567)); //1,234,567 如果我们把 ?= 换成 ?: 的话: function groupByCommas(n) { return n.toString().replace(/\B(?:(\d{3})+(?!\d))/g, ","); } console.log(groupByCommas(1234567)); //1,
兩者的概念不用多說,查到有回答說:區別在於?= 是正向肯定斷言,進行的匹配是不佔查詢長度的;而?: 是非獲取匹配,進行的匹配是佔據查詢長度的。
但是還是不是很理解這裡的查詢佔據長度的說法,對著例子解釋,難道是說第一個例子(?=[^$])匹配的是非結尾,所以123之後的非結尾的長度最小是1個字符,所以把4給一起替代了?那怎麼不直接取代到結尾呢?第二個例子(?=(\d{3}) (?!\d))匹配的是3或3的倍數個數字,直接配對到了結尾,所以把234567也直接取代了?所以我的理解肯定是不對的
理解的不是很透徹,歡迎各位對著例子來解答一下我的困惑,不勝感激!
"123456789".replace(/(d{3})(?:[^$])/g, "$1,");
()
表示捕獲型括號,(?:)
(?表示非捕獲型括號,所以第一個括號匹配的內容會放在$1中,第二個括號匹配的內容不會放在$2
中。d{3}
表示連續三個數字,[^$]
表示匹配一個字符,只要這個字符不是$符號,需要注意的是[]
表示匹配裡面的任意一個字符,但是肯定是要有一個的,所以[]
匹配出來的字符的長度肯定是1,不存在0的情況,另外在[$]
裡面的$符號是沒有特殊含義的,就是$這個字符,而不是匹配字串的結尾。因為
d{3}
匹配三個字符,[^$]
匹配一個字符,所以這個正則匹配4個字符;來看匹配過程,首先"1234"是滿足的,"123"匹配d {3}
,"4"配對[^$]
,此時$1="123"
,所以"1234"被替換成"123,"。然後從5開始下次匹配,類似的"5678"滿足條件,$1="567"
,所以"5678"被替換成"567,"。然後從9開始匹配,下面沒有匹配了,匹配結束,結果為"123,567,9"。"1234567".replace(/B(?:(d{3})+(?!d))/g, ",");
B
匹配非單字邊界,也是一個位置,沒有寬度,(d{3})+
匹配3的倍數數字序列,且個數至少是3個,+
是量詞,表示1到多次,預設是貪婪的,貪婪就是盡可能多的匹配,(?!d)表示這個位置後面不是數字。看例子,首先
B
不匹配行首,所以匹配的位置移動到"1"後面的位置,此時B
匹配1後面的位置,然後"234", "567"匹配d{3} ,因為是貪婪匹配,所以(d{3})+匹配"234567",然後因為7後面是字符串的結尾了,所以滿足斷言(?!d)
不是數字,所以整個正則的匹配結果是"234567",所以"234567"被替換成了","
。 1不動,所以"1234567"變成了"1,"。"123456789".replace(/(d{3})(?=[^$])/g, "$1,");
這個正規表示式不滿足"千分位加號"的需求,"123456789"只是個特例(位數剛好是3的倍數),換成"12345678"結果是"123,456,78"。
佔據或"消耗"的意思是說匹配的部分是否可被其他正則 (後面的斷言,或
/ /g
的下一次) 再匹配。如果"消耗"掉了就不能再配對了。另外例1
[^$]
是匹配一個非$
的字符,和行末無關。
replace(?=456)
符合一個位置,這個位置後面跟了456
。例如
123(?=456)
會匹配123456
中的123
,而不會匹配123457
中的123
,不佔用後面的並不會被佔用掉。123456
配對的是
123456, 而
123(?=456)456
同樣匹配123456
後面加了同樣匹配
123456後面加了
(56)。正規中可以用括號改變優先權等,另外,對於加括號的部分,會從左到右分配遞增的分配一個編號,在後面可以用編號引用這一部分匹配到的文本。在JS
裡,替換的部分可以用
(?:)$1
之類的引用這一部分的匹配。例如
(a)1會匹配兩個連續的a,
([A-Z])1
匹配兩個連續相同的大小字母,(A-Z)1([a-z])2
匹配兩個連續的大小字母,後面跟兩個連續的小寫字母(大小寫字母可以不同)。有時候,我們只想改變優先權,不想分配編號(很少用到),就用
比如
(a)(?:b)(c)12匹配
abcac
,但是(a)(b)(c)12
匹配abcab
.http://zonxin.github.io/post/...
用
()
括住的是可以使用$1(到$9)
去配對的如下面這個,可以使用$1去匹配(捕獲)到括號裡的匹配到的值
,
。使用
(?:)
則是不捕獲這一個。就是不能透過$1
,去取得括號所得到的值上面兩個都是匹配出含
,
的值來看下面這個,
(?=)
是用來匹配,但是不出現在結果裡的。下面這個的結果就沒有,
三個程式碼的結果如圖
這個寫法是很有用的,有些內容不希望出現在結果裡,但是不用它又匹配不全,就可以用這個了
這2個功能毫不相干
模式1
pattern1(?=pattern2)
正向肯定斷言;模式2(?:pattern3)
非捕獲性分組1.
模式1
: pattern2 本身不參與匹配,對pattern1的匹配結果(ret1)進行斷言:字符串中 ret1之後的內容是否匹配pattern2?若是,則ret1為模式1
匹配結果,若否,則ret1不是模式1
匹配結果。當然,不符合pattern1,則不符合模式1
。舉例:
2.
模式2
主要用於區別捕獲性分組(pattern4)
,記為模式3
在數學中小括號用於進行一次優先運算;而
模式3
,除了對代碼進行隔離,pattern4參與了匹配,且對pattern4的匹配結果進行了存儲
對於
模式2
(?:pattern3)的非捕獲性分組,則表示不會對pattern3的結果進行存儲,但本身pattern3參與了匹配,主要用於對代碼進行隔離。也就是要表現
()
本來的意義,而()
在正規表達式中有了捕獲性分組的定義,於是增加一個
?:
以示區別。這和轉義符有異曲同工的妙處。
舉例
@luckness 對題主的內容進行了詳細解答,而我對題主標題進行了解答。