標題挺有意思吧,一個來自正則,一個來自 CSS
。
前者是正則斷言,後者是 CSS
選擇器。
正則是用來做什麼的?匹配字元的。
選擇器是用來做什麼的?匹配元素的。
既然都是用來“匹配”的,那麼,如果二者在一些地方有什麼相似之處,應不足為奇。
我發現 (?<=p)
與 :nth-child()
就有很強的相似性。
這裡容我慢慢道來。
本文假設讀者對 CSS
選擇器更熟悉些,所以下面的例子都是先 CSS
,後正則。
1. 匹配所有元素
假設頁面上有 9
個 li
,讓所有元素的字都變成紅色。此處不會使用 :nth-child
的,直接用標籤選擇器就行了。
li{
color: red;
}
複製程式碼
同樣的,正則這邊也不需要使用 (?<=p)
。
'123456789'.replace(/./g, '*')
// "*********"
複製程式碼
2. 匹配第1個元素
匹配首元素,在CSS
可以用 :first-child
選擇器:
li:first-child{
color:red;
}
複製程式碼
而正則可以使用 ^
位置匹配符:
'123456789'.replace(/^./g, '*')
// "*23456789"
複製程式碼
而我們知道 :first-child
其實是 :nth-child
的特例:
li:nth-child(1){
color:red;
}
複製程式碼
相應的,正則其實也可以用 (?<=p)
:
'123456789'.replace(/(?<=^)./g, '*')
// "*23456789"
複製程式碼
(?<=^)
斷言其實匹配的是一個位置,^
之後的位置,當然還是開頭。可以參考《JS正則迷你書》對位置的講解。
3. 匹配第3個元素
CSS
裡要匹配第 3
個元素,:nth-child(3)
即可
li:nth-child(3){
color:red;
}
複製程式碼
而正則這邊呢?這裡需要轉個彎,要匹配第 3
個,其實是說該字元前面還有 2
個:
'123456789'.replace(/(?<=^.{2})./g, '*')
// "12*456789"
複製程式碼
4. 匹配前3個元素
我們知道 :nth-child
選擇器厲害之處是在於它支援 an+b
表示式,比如匹配前 3
個:
li:nth-child(-n+3){
color:red;
}
複製程式碼
正則這邊,要匹配的字元前面有 0
到 2
個字元,
'123456789'.replace(/(?<=^.{0,2})./g, '*')
// "***456789"
複製程式碼
5. 匹配奇數位
CSS
這邊使用 2n+1
:
li:nth-child(2n+1){
color:red;
}
複製程式碼
正則這邊,要匹配的字元前面有 0
、2
、4
...個字元,
'123456789'.replace(/(?<=^(.{2})*)./g, '*')
// "*2*4*6*8*"
複製程式碼
類似的匹配偶數位,即要匹配的字元前面有 1
、3
、5
...個字元:
'123456789'.replace(/(?<=^(.)(.{2})*)./g, '*')
// "1*3*5*7*9"
複製程式碼
6. 更一般的 an+b
比如 CSS
這邊使用 4n+3
li:nth-child(4n+3){
color:red;
}
複製程式碼
正則這邊變成了:
'123456789'.replace(/(?<=^(.{4})*.{2})./g, '*')
// "12*456*89"
複製程式碼
即:要匹配的字元前面還有 4n+2
個字元
7. (?=p) 與 :nth-last-child
我們知道 :nth-child
還有對應的 :nth-last-child
。它的意思是,與 :nth-child
相反,不是從前往後數,而是從後面向前數,比如要匹配後 3
個 li
:
li:nth-last-child(-n+3){
color:red;
}
複製程式碼
正則這邊呢?(?<=p)
表示 p
後面的位置,與之相對的是 (?=p)
,表示 p
前面的位置。因此要匹配後 3
個字元:
'123456789'.replace(/.(?=.{0,2}$)/g, '*')
// "123456***"
複製程式碼
更多的,與前幾條類似,這裡就不寫了。
8. (?<!p) 與 :not(:nth-child())
在 CSS
中,要匹配除了第 3
個元素之外的所有元素,可以配合使用 :not
選擇器來實現“補集”。
li:not(:nth-child(3)){
color:red;
}
複製程式碼
(?<=p)
表示 p
後面的位置。而 (?<!p)
有點繞,它表示所有位置中,不是 p
後面的那個位置,或者說當下位置的前面不是 p
。
'123456789'.replace(/(?<!^.{2})./g, '*')
// "**3******"
複製程式碼
9. :nth-child(n+3):nth-child(-n+7)
:nth-child
除了取補,還可以取交集,比如匹配第 3
-7
個元素
li:nth-child(n+3):nth-child(-n+7){
color:red;
}
複製程式碼
(?<=p)
也可以支援交集的
'123456789'.replace(/(?<=^.{2,})(?<=^.{0,6})./g, '*')
// "12*****89"
複製程式碼
交併補,還有並集,CSS
很簡單:
li:nth-child(3),
li:nth-child(7){
color:red;
}
複製程式碼
正則呢,有 |
就是來做這個:
'123456789'.replace(/(?<=^(.{2}|.{6}))./g, '*')
// "12*456*89"
複製程式碼
自此,這麼一條條看下來,發現了二者確實有多相似之處。
這種跨界比較,我覺得很有趣!
本文完。
另外,歡迎繼續閱讀本人的《JS正則迷你書》。