直接上例子:每三個數字中間加逗號
"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也直接取代了?所以我的理解肯定是不對的
理解的不是很透徹,歡迎各位對著例子來解答一下我的困惑,不勝感激!
怪我咯2017-06-15 09:24:42
"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"。
typecho2017-06-15 09:24:42
佔據或"消耗"的意思是說匹配的部分是否可被其他正則 (後面的斷言,或/ /g
的下一次) 再匹配。如果"消耗"掉了就不能再配對了。
"123456789".replace(/(\d{3})(?=[^$])/g, (m, ) => `{matched=${m} =${}}`);
// => '{matched=123 =123}{matched=456 =456}789'
// (?=) 第一次没有消耗掉4, 第二次会从456..开始
"123456789".replace(/(\d{3})(?:[^$])/g, (m, ) => `{matched=${m} =${}}`);
// => '{matched=1234 =123}{matched=5678 =567}9'
// (?:) 第一次消耗掉4,第二次会从567..开始
另外例1 [^$]
是匹配一個非$
的字符,和行末無關。
巴扎黑2017-06-15 09:24:42
(?=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/...
世界只因有你2017-06-15 09:24:42
用()
括住的是可以使用$1(到$9)
去配對的
如下面這個,可以使用$1去匹配(捕獲)到括號裡的匹配到的值,
。
a = '123,456';
a.match(/\d{3}(,)/)
使用(?:)
則是不捕獲這一個。就是不能透過$1
,去取得括號所得到的值
a.match(/\d{3}(?:,)/)
上面兩個都是匹配出含,
的值
來看下面這個,(?=)
是用來匹配,但是不出現在結果裡的。下面這個的結果就沒有,
a.match(/\d{3}(?=,)/)
三個程式碼的結果如圖
這個寫法是很有用的,有些內容不希望出現在結果裡,但是不用它又匹配不全,就可以用這個了
世界只因有你2017-06-15 09:24:42
這2個功能毫不相干
模式1pattern1(?=pattern2)
正向肯定斷言;模式2(?:pattern3)
非捕獲性分組
1.模式1
: pattern2 本身不參與匹配,對pattern1的匹配結果(ret1)進行斷言:字符串中 ret1之後的內容是否匹配pattern2?若是,則ret1為模式1
匹配結果,若否,則ret1不是模式1
匹配結果。當然,不符合pattern1,則不符合模式1
。
舉例:
var str1='abc',str2='acb';var reg=/a(?=b)/
console.log(reg.test(str1),reg.test(str2)) //=>true false
//因为reg.test(str1)为真,输出匹配结果
console.log(str1.match(reg)[0]) //=>a
2.模式2
主要用於區別捕獲性分組(pattern4)
,記為模式3
在數學中小括號用於進行一次優先運算;而模式3
,除了對代碼進行隔離,pattern4參與了匹
配,且對pattern4的匹配結果進行了存儲
對於模式2
(?:pattern3)的非捕獲性分組,則表示不會對pattern3的結果進行存儲,但本身
pattern3參與了匹配,主要用於對代碼進行隔離。也就是要表現()
本來的意義,而()
在正規
表達式中有了捕獲性分組的定義,於是增加一個?:
以示區別。這和轉義符有異曲同工的妙處。
舉例
var str='abc'
var reg1=/(\w)(\w)(\w)/
var reg2=/(\w)(?:\w)(\w)/
//捕获了3次,RegExp.,RegExp.,RegExp....依次存储捕获结果
var ret1=str.match(reg1)
console.log(RegExp.,RegExp.,RegExp.)//=>a b c
var ret2=str.match(reg2)
//捕获了2次
console.log(RegExp.,RegExp.) //=>a c
@luckness 對題主的內容進行了詳細解答,而我對題主標題進行了解答。