關於正則表示式的先行斷言(lookahead)和後行斷言(lookbehind)的理解
正則表示式的先行斷言和後行斷言一共有4種形式:
(?=pattern) 零寬正向先行斷言(zero-width positive lookahead assertion)
(?!pattern) 零寬負向先行斷言(zero-width negative lookahead assertion)
(?<=pattern) 零寬正向後行斷言(zero-width positive lookbehind assertion)
(?<!pattern) 零寬負向後行斷言(zero-width negative lookbehind assertion)
這裡面的pattern是一個正則表示式。
如同^代表開頭,$代表結尾,\b代表單詞邊界一樣,先行斷言和後行斷言也有類似的作用,它們只匹配某些位置,在匹配過程中,不佔用字元,所以被稱為“零寬”。所謂位置,是指字串中(每行)第一個字元的左邊、最後一個字元的右邊以及相鄰字元的中間(假設文字方向是頭左尾右)。
下面分別舉例來說明這4種斷言的含義。
(?=pattern) 正向先行斷言
代表字串中的一個位置,緊接該位置之後的字元序列能夠匹配pattern。
例如對”a regular expression”這個字串,要想匹配regular中的re,但不能匹配expression中的re,可以用”re(?=gular)”,該表示式限定了re右邊的位置,這個位置之後是gular,但並不消耗gular這些字元,將表示式改為”re(?=gular).”,將會匹配reg,元字元.匹配了g,括號這一砣匹配了e和g之間的位置。
(?!pattern) 負向先行斷言
代表字串中的一個位置,緊接該位置之後的字元序列不能匹配pattern。
例如對”regex represents regular expression”這個字串,要想匹配除regex和regular之外的re,可以用”re(?!g)”,該表示式限定了re右邊的位置,這個位置後面不是字元g。負向和正向的區別,就在於該位置之後的字元能否匹配括號中的表示式。
(?<=pattern) 正向後行斷言
代表字串中的一個位置,緊接該位置之前的字元序列能夠匹配pattern。
例如對”regex represents regular expression”這個字串,有4個單詞,要想匹配單詞內部的re,但不匹配單詞開頭的re,可以用”(?<=\w)re”,單詞內部的re,在re前面應該是一個單詞字元。之所以叫後行斷言,是因為正則表示式引擎在匹配字串和表示式時,是從前向後逐個掃描字串中的字元,並判斷是否與表示式符合,當在表示式中遇到該斷言時,正則表示式引擎需要往字串前端檢測已掃描過的字元,相對於掃描方向是向後的。
(?<!pattern) 負向後行斷言
代表字串中的一個位置,緊接該位置之前的字元序列不能匹配pattern。
例如對”regex represents regular expression”這個字串,要想匹配單詞開頭的re,可以用”(?<!\w)re”。單詞開頭的re,在本例中,也就是指不在單詞內部的re,即re前面不是單詞字元。當然也可以用”\bre”來匹配。
對於這4個斷言的理解,可以從兩個方面入手:
1.關於先行(lookahead)和後行(lookbehind):正則表示式引擎在執行字串和表示式匹配時,會從頭到尾(從前到後)連續掃描字串中的字元,設想有一個掃描指標指向字元邊界處並隨匹配過程移動。先行斷言,是當掃描指標位於某處時,引擎會嘗試匹配指標還未掃過的字元,先於指標到達該字元,故稱為先行。後行斷言,引擎會嘗試匹配指標已掃過的字元,後於指標到達該字元,故稱為後行。
2.關於正向(positive)和負向(negative):正向就表示匹配括號中的表示式,負向表示不匹配。
對這4個斷言形式的記憶:
1.先行和後行:後行斷言(?<=pattern)、(?<!pattern)中,有個小於號,同時也是箭頭,對於自左至右的文字方向,這個箭頭是指向後的,這也比較符合我們的習慣。把小於號去掉,就是先行斷言。
2.正向和負向:不等於(!=)、邏輯非(!)都是用!號來表示,所以有!號的形式表示不匹配、負向;將!號換成=號,就表示匹配、正向。
我們經常用正則表示式來檢測一個字串中包含某個子串,要表示一個字串中不包含某個字元或某些字元也很容易,用[^...]形式就可以了。要表示一個字串中不包含某個子串(由字元序列構成)呢?
用[^...]這種形式就不行了,這時就要用到(負向)先行斷言或後行斷言、或同時使用。
例如判斷一句話中包含this,但不包含that。
包含this比較好辦,一句話中不包含that,可以認為這句話中每個字元的前面都不是that或每個字元的後面都不是that。正則表示式如下:
^((?<!that).)*this((?<!that).)*$ 或 ^(.(?!that))*this(.(?!that))*$
對於”this is the case”這句話,兩個表示式都能夠匹配成功,而”note that this is the case”都匹配失敗。
在一般情況下,這兩個表示式基本上都能夠滿足要求了。考慮極端情況,如一句話以that開頭、以that結尾、that和this連在一起時,上述表示式就可能不勝任了。
如”note thatthis is the case”或者”this is the case, not that”等。
只要靈活運用這幾個斷言,就很容易解決:
^(.(?<!that))*this(.(?<!that))*$
^(.(?<!that))*this((?!that).)*$
^((?!that).)*this(.(?<!that))*$
^((?!that).)*this((?!that).)*$
這4個正則表示式測試上述的幾句話,結果都能夠滿足要求。
上述4種斷言,括號裡的pattern本身是一個正則表示式。但對2種後行斷言有所限制,在Perl和Python中,這個表示式必須是定長(fixed length)的,即不能使用*、+、?等元字元,如(?<=abc)沒有問題,但(?<=a*bc)是不被支援的,特別是當表示式中含有|連線的分支時,各個分支的長度必須相同。之所以不支援變長表示式,是因為當引擎檢查後行斷言時,無法確定要回溯多少步。Java支援?、{m}、{n,m}等符號,但同樣不支援*、+字元。Javascript乾脆不支援後行斷言,不過一般來說,這不是太大的問題。
相關推薦
關於正則表示式的先行斷言(lookahead)和後行斷言(lookbehind)的理解
正則表示式的先行斷言和後行斷言一共有4種形式: (?=pattern) 零寬正向先行斷言(zero-width positive lookahead assertion) (?!pattern) 零寬負向先行斷言(zero-width negative lookahe
深入JS正則先行和後行斷言
如果 空格 master 文本 密碼 trac 開頭 是我 gre 這裏是 Mastering Lookahead and Lookbehind 文章的簡單翻譯,這篇文章是在自己搜索問題的時候stackoverflow上回答問題的人推薦的,看完覺得寫得很不錯。這裏的簡單翻譯
先行斷言和後行斷言
script 字符串 pre ring ctu lac them 引擎 have 後行斷言 JavaScript 語言的正則表達式,只支持先行斷言(lookahead)和先行否定斷言(negative lookahead),不支持後行斷言(lookbehind)和後行否定斷
Python正則表示式的簡單應用和示例演示
前一陣子小編給大家連續分享了十篇關於Python正則表示式基礎的文章,感興趣的小夥伴可以點選連結進去檢視。今天小編給大家分享的是Python正則表示式的簡單應用和示例演示,將前面學習的Python正則表示式做一個概括。 下面的栗子是用於提取高考日期,一般來說,我們填寫日期都會寫2018年6月7日,但
使用正則表示式去掉字串前面和後面多餘的0
記錄一下小的工具程式碼 1、去掉字串前邊的0 String str = "000000021"; String newStr = str.replaceAll("^(0+)", ""); System.out.println(newStr); 2、去掉字串後邊的0 String str
Java中正則表示式相關類Pattern和Matcher的使用
在Java中,java.util.regex包定義了正則表示式使用到的相關類,其中最主要的兩個類為:Pattern、Matcher: Pattern 編譯正則表示式後建立一個匹配模式; Matcher 使用Pattern例項提供的正則表示式對目標字串進行匹
正則表示式去除a標籤和img標籤原始碼
public class TestString { public static void main(String[] args) { String s = "<a href=hjkhkhhk>daafadfafdadfa</a></a><img src='d
關於正則表示式的一些符號和sed、awk的速查筆記
之前轉載了一篇文章詳細講解正則表示式,傳送門:https://blog.csdn.net/CHEndorid/article/details/82932455,本文針對一些常用的進行梳理,並新增sed、awk簡單的操作,作為一個速查筆記 //裡的就是正則表示式 ^表示行
用js以及正則表示式實現對郵箱和密碼的前端驗證
<!DOCTYPE html> <html> <head> <title>郵箱註冊</title> <style type="text/css"> td{ text-align: center; color
正則表示式匹配中英文 字母和數字
在做專案的過程中,使用正則表示式來匹配一段文字中的特定種類字元,是比較常用的一種方式,下面是對常用的正則匹配做了一個歸納整理。 1、匹配中文:[\u4e00-\u9fa5] 2、英文字母:[a-zA-Z] 3、數字:[0-9] 4、匹配中文,英文字母和數字及下劃線:^[
正則表示式的基本語法和在Python下的使用
正則表示式基本語法 常用正則表示式符號 符號 說明 舉例 literal 匹配字串的值 Foo re1|re2 匹配正則表示式re1或re2 fo
python正則表示式擴充套件符號擴充套件和一些訓練小mark
關於正則式的簡要介紹: 1.擴充套件符號 2.一些正則式訓練 # -*- coding: utf-8 -*- """ Created on Sat Jan 6 19:20:43 2018 @
正則表示式在js端和java端的應用
一、介紹 有的時候需要使用正則表示式在js端和java端來判斷一些變數,在這裡面記錄一下js端和java端的使用方法 二、js端正則表示式的應用 注意:js端定義正則(兩遍需要有/) var regex = /^[1-9]\d*$/; //js端判斷輸入框是否滿足正則要求 v
python正則表示式的懶惰匹配和貪婪匹配
第一次碰到這個問題的時候,確實不知道該怎麼辦,後來請教了一個大神,加上自己的理解,才瞭解是什麼意思,這個東西寫python的會經常用到,而且會特別頻繁,在此寫一篇部落格,希望可以幫到一些朋友。例:一個字串 “abcdacsdnd” ①懶惰匹配 regex
正則表示式解決身份證號碼和手機號
首先最後是這樣子的 手機號: return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') 身份證號: return idcard.replace(/(\w{4})\w{10}(\w{4})/, '$1****$2') 比如說, /(\d{3
關於正則表示式——捕獲型括號和非捕獲型括號
對於括號中的子表示式,正則表示式會將匹配的子表示式進行儲存。 <pre class="javascript" name="code">var regular = /^Subject:(\d)/ var str = "Subject:1 as something"
Python正則表示式--每日一點 檢索和替換
簡單的對上期的search和match進行一下簡單補充,兩者最大的區別在於match是從開始部分進行匹配,沒有匹配到就返回空,而search是整句掃描進行匹配 好了,開始今天的內容 大
[Happy Coding] 一個正則表示式,支援邏輯和關係運算符組成的表示式計算
I. 寫一個正則表示式,要求判斷一個數是否滿足以下條件: >= val1 && < val2 ... 1. val1和va2要求支援浮點數; 2. 支援>, >=, <, <=, =, !=關係運算符; 3. 支援&
正則表示式之分組(捕獲)、後向引用
分組 正則表示式中的分組又稱為子表示式,就是把一個正則表示式的全部或部分當做一個整體進行 處理,分成一個或多個組。其中分組是使用“()”表示的。進行分組之後“()”裡面的內容就會被當 成一個整體來處理。 先看看一個
餓了麼元件庫element-ui正則表示式驗證表單,後端驗證表單
vue+elementui 提高開發效率,以下為form表單驗證例子。包含自定義驗證等。 1. 以中國大陸手機號驗證為例 // 這是組價的程式碼 <el-form-item prop="mobile"> <el-input type="text