正則表達式之位置匹配

sharplook夏洛克做爲專業的日誌採集分析系統,涉及的技術點,從後到前着實很多,內容也較爲複雜。正則做爲日誌解析的手段,起着舉足輕重的做用,在此小生將晦澀難懂的內容,拆解出來以便學習之用。javascript

往期回顧

在上一篇文章中,咱們已經學習了正則表達式的字符匹配,介紹了模糊匹配、字符組和量詞。正則表達式就是匹配模式,要麼匹配字符,要麼匹配位置,牢記這個基準。本章小生將介紹位置匹配,將分紅如下內容進行介紹:java

  • 位置的定義
  • 位置如何匹配
  • 位置的特性

位置的定義

位置能夠理解爲字符之間的位置,也能夠稱爲錨點。如圖,箭頭所指的位置:正則表達式

postion-def

位置如何匹配

在ES5中,共有6個錨:^$\b\B(?=p)(?!p)工具

^$\b\B(?=a)(?!b) 其可視化的形式以下:其可視化的形式以下:post

anchors

^$

^(脫字符)匹配開頭的位置,在多行匹配中匹配行開頭。學習

$(美圓符)匹配結尾的位置,在多行匹配中匹配行結尾。spa

好比咱們把字符串的開頭和結尾替換爲#,就是將位置替換爲字符:日誌

let result = 'lemon'.replace(/^|$/g, '#');
console.log(result);
// => #lemon#

多行匹配模式(增長修飾符 m)時,此是行的概念,這一點須要咱們注意:code

let result = 'I\nlove\njavascript'.replace(/$|^/gm, '#');
console.log(result);
/*
#I#
#love#
#javascript#
*/

\b\B

\b 是單詞邊界符,具體爲\w\W之間的位置,也包括\w^之間的位置,和\w$之間的位置。regexp

好比,咱們經過字符串替換字符串中的\b位置爲#來進行分析:

let result = '[JS] Lesson_01.mp4'.replace(/\b/g, '#');
console.log(result);
// => [#JS#] #Lesson_01#.#mp4#

具體怎麼匹配成這樣的? 接下來咱們慢慢來分析。

首先咱們須要知道,\w 是字符組 [a-zA-Z0-9_]的簡寫,也就是\w是字母、數字和下劃線中的任何一個。而 \W 是排除字符組 [^a-zA-Z0-9_]的簡寫形式,即\W\w之外的任何一個字符。

咱們再來看咱們的結果[#JS#] #Lesson_01#.#mp4#中的每個#的由來:

  • 第一個,兩邊字符是 [J,是 \W\w 之間的位置。
  • 第二個,兩邊字符是 S],是 \w\W 之間的位置。
  • 第三個,兩邊字符是空格與 L,是 \W \w 之間的位置。
  • 第四個,兩邊字符是 1.,是 \w\W 之間的位置。
  • 第五個,兩邊字符是 .m,是 \W\w之間的位置。
  • 第六個,位於結尾,前面的字符 4\w,即 \w$ 之間的位置。

知道了 \b 的概念以後,接下來 \B 就很好理解了。\B 就是 \b 的反面意思,非單詞邊界,例如上例子中除去 \b 的位置以外,餘下的就都是 \B 的位置了。具體來講就是 \w\w\W\W^\W\W$ 之間的位置。

好比,上例子中,把全部 \B 替換成 #:

let result = '[JS] Lesson_01.mp4'.replace(/\B/g, '#');
console.log(result);
// => #[J#S]# L#e#s#s#o#n#_#0#1.m#p#4

(?=p)(?!p)

(?=p),其中 p 是一個子模式,即 p 前面的位置,或者說,該位置後面的字符要匹配 p。好比(?=l),表示 l 字符前面的位置,例如:

let result = 'lemon'.replace(/(?=l)/g, '#');
console.log(result);
// => #lemon

(?!p) 就是(?=p) 的反面意思,好比:

let result = 'lemon'.replace(/(?!l)/g, '#');
console.log(result);
// => l#e#m#o#n#

兩者的學名分別是positive lookahead 和 negative lookahead。中文意思分別爲正向先行斷言和負向先行斷言。ES5以後的版本,會支持positive lookbehind 和 negative lookbehind。意思是正向後行斷言和負向後行斷言。具體是(?<=p)(?<!p)。例如:

let result = 'lemon'.replace(/(?<=l)/g, '#');
console.log(result);
// => l#emon

表示該位置以前的字符要匹配 l 表達式。而 (?<!p) 爲:

let result = 'lemon'.replace(/(?<=l)/g, '#');
console.log(result);
// => #le#m#o#n#

表示該位置以前的字符不能匹配 l

其實 (?=p)^ 同樣好理解,將其理解成 p 前面的那個位置便可,其餘相似。

位置的特性

對於位置的理解,咱們能夠將其理解成空字符 ""。 好比lemon 字符串能夠寫成以下的形式:

'lemon' === '' + 'l' + 'e' + 'm' + 'o' + 'n'+ '';

也能夠寫成以下:

'lemon' === '' + 'lemon' + '';

所以,把 ^lemon$ 寫成 ^^lemon$$$,是沒有任何問題的:

let result = /^^lemon$$/.test('lemon');
console.log(result);
// => true

甚至能夠寫成更復雜的:

let result = /(?=le)^^le(?=\w)mon$\b\b$/.test('lemon');
console.log(result);
// => true

也就是說字符之間的位置,能夠寫成多個。

把位置理解成空字符,是對位置很是有效的理解方式。

小結

本節介紹了位置的匹配,須要諸君理解 ^$\b\B(?=p)(?!p)(?<=p)(?<!p)中的位置匹配的用法。

本文中的正則表達式轉化爲關係圖來展現的工具是Regexper

此文主要參考和學習了老姚的《JavaScript 正則表達式迷你書》,內容清晰明瞭,在此很是感謝老姚的 free精神,致敬。

參考文獻

[1] 老姚 著《JavaScript 正則表達式迷你書》

相關文章
相關標籤/搜索