正則表達式斷言精講Java語法實現

2020-12-23 計算機java編程

斷言

本文目的是講解正則表達式之斷言用法。目前網際網路上有很多博文對斷言講解的並不透徹,如果您剛開始學習斷言,相信此博文會對您有幫助。

1.2.3.1 情景導入

假設,我要獲得一個字符串裡面所有以空格開頭的英文詞語。

在使用上面的代碼過程中存在一些問題,我獲得的單詞默認是前頭帶空格的,縱然我可以通過String類的trim來解決這些問題,可是這樣用起來會很麻煩,有沒有一種正則表達式的規則可以檢測那些開頭帶空格的詞彙但是適配到的詞彙不帶空格呢?答案是有的,那就是斷言

什麼是斷言

在使用正則表達式時,有時我們需要捕獲的內容前後必須是特定內容,但又不捕獲這些特定內容的時候,零寬斷言就起到作用了。

斷言全稱為零寬斷言

斷言的語法規則

零寬斷言為什麼叫零寬斷言

理解這一點至關重要,拿零寬前行正向斷言來舉例

零寬

零寬的含義為斷言部分不佔據寬度,舉個例子12(?=la)匹配12la匹配到的是12,含義是la前面的12。

12la匹配12la匹配到的是12la,含義為匹配value為12la的字符串。不知道通過這個例子你能否看懂零寬的意義,不懂也沒關係,看完接下來幾章就會懂了。

前行

前行的含義我可以確定我說的是正確的,現在網際網路上好多人對前行的理解是錯誤的,雖然按照他們的解釋是可以解釋的通大多數情況,但是我們還是要抱著實事求是的態度,還原前行真正的含義,參考網站:正則表達式零寬斷言詳解(?=,?<=,?!,?,Regular expression to match a line that doesn't contain a word。

在正則表達式中,每個字符串都是有定位的,所謂定位,就是確定字符串中每個字符位置的數字,這個只可意會,我給您看幾張圖,通過圖片,或許可以理解

看到沒有,字符串每一個字符間隔就是一個個位置點,字符串第一個字符前為位置0,字符串第一個字符和第二個字符之間為位置1,字符串第一個字符位於位置0和位置1之間,以此類推……

前行的意義為位置之前,後行的意義為位置之後

如上圖,位置5位於紅色區域後行,位置5位於黃色區域前行

那麼,在斷言中前行和後行代表著什麼呢?

比如說正則表達式12(?=la)在匹配字符串qwew12bb12la的時候,他會先,匹配到從左往右第一個12,如下圖所示

因為(?=x)是前行匹配,這個時候12是佔位置的,位置點走到了第一個12的後面,即位置6,。因為是零寬,(?=la)不佔位置,接下來以位置6為前行,匹配位置6的後面,位置6的後面不是la,故不匹配位置6前面的12,接下來位置轉到了第二個12後面,如下圖所示

因為是前行匹配,位置10作為前行,匹配後面的字符,後面是la符合要求,因為零寬,匹配到的最終字符不包括零寬,如下圖所示

不懂也沒關係,看完接下來幾章就會懂了。

負向

所謂負向,不符合為負向,如(?<!x)

就是負向,該斷言匹配的是不符合x標準的字符串作為目標字符串的後行

再來熟悉一下幾個斷言

斷言DEMO

後行正向斷言,該斷言匹配前面是aa的字符

運行結果為

dfdsfs

後行負向斷言,該斷言匹配的是前面不是$的數字

運行結果為

matcher1.group() = 23

我來解釋一下,正則表達式(?<!\\$|\\d)\\d+,斷言的意思是不匹配前面為$或數字的數字。

模擬一下匹配的過程,也許會更加明白是怎麼一回事兒,先說一下"$14 23",位置我就不在圖中標了,自己數一下吧

(?<!\\$|\\d)\\d+先匹配數字,匹配到了1,位置是1,因為斷言是不佔寬度的。因為是後行,檢測到左邊是,符合要求,故匹配23

先行正向斷言

運行結果是

matcher2.group() = windows

我來稍微解釋一下,"(?i)windows(?=2000|xp|10)"(?i)表明不區分大小寫,Windows表明適配windows,(?=2000|xp|10)表明是零寬先行正向斷言。我說一下匹配的過程,首先匹配windows,位置來到了windows後,零寬先行,後面是xp適配成功。

先行負向斷言

運行結果是

matcher3.group() = linux

這個就不解釋了,自行理解吧

以上四個demo是最最基礎的demo,在很多教程上對斷言的講解止步於此(實際上,很短教程連最基本的匹配過程都沒講,只講了匹配的結果,這個要出大問題的),務須掌握好上面的四個demo。

斷言的基礎應用和實際用處

放一張思維導圖

這個我先說一下結論,在實際應用開發中,在應用諸如驗證開頭或結尾(只要求一行的開頭或結尾)的實踐中,大概有兩種,一種是零寬,一種是非零寬。所謂零寬即匹配的數據不包括斷言,非零寬反之,在某些情況下需要藉助String方法的subString()方法。

一般情況下,使用斷言,主要是用它零寬的屬性,驗證開頭包含,結尾包含時一般不用斷言,分組就能解決問題,當開頭不包含或結尾不包含等問題時,使用斷言是很好的辦法。

演示三個

驗證不包含

運行結果如下

驗證不包含 matcherError.group() = wqeqr12eqr34512 !"wqer12335".contains("123") = false

解析:正則表達式裡字符串"不包含"匹配技巧 | 外刊IT評論

驗證開頭包含

一行字符串,驗證開頭是否包含某字符串,若包含則輸出匹配到的數據,此方法會包括斷言。也就是說假如驗證「123erre」的開頭是否是123,匹配到的數據為123erre而不是erre。驗證開頭包含且匹配數據不包括斷言請看下一章

結果如下

驗證開頭包含 falsematcherRight.group() = wercdv

解析:

^(?=wer).*匹配wercdv的時候,先因為^來到了位置0,位置0後面是符合.*的,遂開始匹配斷言,注意這時候位置依然在位置0,因為是先行斷言,位置0後面是wer符合斷言要求,故匹配到了wercdv

驗證開頭包含且匹配到的數據不包括斷言

假如說要匹配開頭是wer的字符串,字符串是wercdv,匹配到的是cdv而不是wercdv

結果如下

驗證開頭包含,匹配到的數據不包括斷言false matcherRight.start() = 0matcherRight.end() = 6matcherRight.group() = cdv

解析:

^wer(?<=wer)(.*)因為^所以先來到了位置0,然後匹配wer,來到了位置3,位置3後面符合.*的要求,因為後行匹配,前面是wer,符合要求,在取出的過程中,有一個分組,選取的是.*故最終取出cdv

驗證結尾包含,且匹配到的數據不包括斷言

舉個例子,匹配以「元」結尾的詞彙,且匹配到的數據不包括「元」,譬如「12元」,匹配到的數據是12。

運行結果是

驗證結尾包含,且獲得結尾之前的數字matcherRight.group(1) = 12

解析:

(\\d+)(?=元).$因為$先來到位置3,如圖所示

然後因為(\\d+)(?=元).$的.,位置向前一步,來到了位置2,然後前行斷言,位置2的後面是元,前面是數字符合要求,如下圖所示

匹配到了「12元」,因為輸出組①,故最終輸出12。

斷言基礎應用總體代碼

代碼文件,運行結果寫在了注釋裡面

不按套路出牌,幫你徹底理解斷言

一般情況下,使用斷言,主要是用它零寬的屬性,向驗證開頭包含,結尾包含時一般不用斷言,分組就能解決問題,當開頭不包含或結尾不包含等問題時,使用斷言是很好的辦法。

絕大多數網站在講解斷言問題的時候總是去引用斷言demo一章裡面那四個例子,這會給人造成一種「前行斷言適配結尾,後行斷言適配開頭」的錯覺,事實上並不是這個樣子,重要的是要具體問題具體分析。如同上面的代碼,不按所謂常理出牌,有助於正則表達式之理解。

上面取了四個例子,皆不按套路來,為方便理解,選一個細講

運行結果

不按套路來的零寬後行負向斷言 matcher3.group() = lla

(?i)\\w+(?<!re)a的本意是不區分大小寫地去適配結尾是a且a的前面不是re的字符。(?!)是不區分大小寫的意思。正則發揮作用時,先找到a,位置來到a的前面,因為後行斷言,位置的前面不能是re。因為\\w+,a的前面需要是字母或數字。綜合看來,意思是a的前面是除re之外的字母或數字。

如果真的不理解,就死記下面的實例

不包含a

開頭不包含a

結尾不包含a

包含a且不包含b

處於a和b之間

適配字符串中所有不以b結尾的數字

適配字符串中所有以a開頭的數字

在某些時候亦可以用\b來實現某些可以用斷言實現的正則表達,舉個例子

獲取所有以b結尾的數字

查看代碼:

相關焦點

  • java正則表達式入坑指南
    在日常開發工作中,無論你使用的語言是java、python、shell、golang還是C#, 正則表達式是程式語言中幾乎繞不開的話題。有了它,可以幫你快速定位到符合條件的文本內容。今天小編帶大家一起來學習下正則表達式,相信通過這篇文章的介紹,能為以後的工作提供一個更清晰的思路。
  • Python中使用re模塊實現正則表達式的匹配字符串操作
    第八十二節:匹配字符串經過上一節比較枯燥的基礎內容,今天來看看如何利用正則表達式在Python中進行具體操作。在Python中使用正則表達式,首先要導入一個re模塊。re就是Regular Expression(正則表達式)的縮寫,所以導入re模塊就是導入「正則表達式模塊」。導入re模塊的代碼比較簡單,它是這樣的:Import re今天的學習內容就是使用正則表達式匹配字符串。
  • Python中使用re模塊實現正則表達式的分割字符串操作
    第八十四節:正則表達式實現分割字符串操作分割字符串的方法在前面就學習過,用正則表達式實現分割字符串,使用的依然是split()方法,分割後也是返回一個列表,不同點在哪裡呢?先回憶一下直接使用split()方法分割字符串的語法格式
  • Python中使用re模塊實現正則表達式的替換字符串操作
    第八十三節:替換字符串Python中,導入re模塊後還可以進行字符串的替換操作,就是sub()方法,具體的語法格式如下:re.sub(pattern,repl,str,count,flags)>和昨天學過的三種匹配字符串的方法一樣,模塊名re使用一個點「.」和方法名sub連接;方法名sub後的小括號可以設置五個參數,前三個必備,後兩個可選,中間使用逗號「,」分隔;第一個參數是老熟人pattern,代表正則表達式轉換的模式字符串;
  • Python正則表達式由淺入深(三)
    經過前面三篇連載文章,相信大家對Python的re模塊使用正則表達式來匹配字符串已經有所了解。到目前為止,基本上有難度入門知識點都已經學完,我們繼續補充還沒講到的知識點,包括:行定位符與轉義字符,以及re模塊的re.sub()方法和re.split()方法。
  • python正則表達式使用方法說明
    曾光紅/文 (同步發布豆瓜網)一、導入re庫python使用正則表達式要導入re庫。import re在re庫中。正則表達式通常被用來檢索查找、替換那些符合某個模式(規則)的文本。2.星號「*」一個星號可以表示它前面的一個子表達式(普通字符、另一個或幾個正則表達式符號)0次到無限次。3.問號「?」問號表示它前面的子表達式0次或者1次。注意,這裡的問號是英文問號。
  • JavaScript-正則表達式中的修飾符和對象有哪些?
    1.2 正則表達式基本語法正則表達式的基本語法語法:/正則表達式主體/修飾符(可選)例如:var frk_reg = /frank/gi;其中:/正則表達式主體/修飾符(可選),這種創建正則的方法我們稱之為【字面量創建正則表達式】。
  • Python正則表達式由淺入深(一)
    幸運的是Python提供了re模塊,可以實現正則表達式的操作。re模塊主要通過六大方法來對字符串進行處理,包括:match()、search()、findall()、split()、sub()。這些方法涉及到字符串的匹配與替換等操作,在接下來的4篇連載文章裡,我們不單只會講解這4種方法,還會把元字符、行定位符、限定符、字符類、排除字符、選擇字符、轉義字符、分組等正則表達式最常用知識點貫穿起來。
  • Python學習第137課——正則表達式中實現可選規則
    正則表達式英文是Regular Expression,各種程式語言中都是把它簡寫成Regex,或者Regexp或者re。這節我們學習如何在正則表達式中實現可選規則。●用小括號和pipe(豎線|)實現每一個可選項例1:現在假設我們有一個應答機器人,接到了很多很多用戶的留言,這些留言中包括用戶自己的姓名、聯繫電話等信息。
  • 學習爬蟲的第49天,正則表達式被我踩在腳下
    好在有朋友在評論區告訴我:不用太在乎 bs4 了,正則表達式學好就行了,效率不是 bs4 可以比的。一下子點燃了我前進的道路、又讓我變得元氣滿滿。巧合的是,今天老師就開始講正則表達式了,這就是命中注定吧。
  • Python正則表達式:特殊符號和字符
    正表達式為高級的文本模式匹配,抽取,與/或文本形式的搜索和替換功能提供了基礎。簡而言之,正則表達式(簡稱regex)是由一些字符和特殊符號組成的字符串,它描述了模式的重複或者表達多個字符。python通過標準庫中的re模塊來支持正則表達式。
  • Python正則表達式由淺入深(二)
    在前兩篇連載文章中,我們學習了re模塊的match()、search()、findall()方法,以及學習了使用正則表達式中常用的元字符、限定符、選擇字符、中括號來搭配這些方法來靈活處理常見的數據匹配問題。這本篇文章分鐘,我們將會進一步學習正則表達式中其他符合,包括令初學者非常頭疼的分組問題。
  • PHP正則表達式及表單註冊案例
    正則表達式是一種具有特定模式的用來匹配文本的字符串
  • 【外文翻譯】外國友人寫得很不錯的Java Lambda表達式入門教程,我終於翻譯好給大家啦!!!
    「英語原文的連結在最底下的「閱讀原文」」簡介(譯者認為: 超過 3 行的邏輯就不適用 Lambda 表達式了。雖然看著很先進,其實 Lambda 表達式的本質只是一個 " 語法糖 ", 由編譯器推斷並幫你轉換包裝為常規的代碼, 因此你可以使用更少的代碼來實現同樣的功能。
  • 怎樣用正則表達式判斷輸入框中是否是車牌號
    【判斷輸入是否是五個字母和數字】第二步就是我們用正則方法判斷輸入的內容具體是什麼,我們var re = new RegExp('^[A-Za-z0-9]{5}$');這樣寫是判斷輸入的內容是五個字母加數字
  • Javaweb開發學習路線及Java三大框架分享
    Java在客戶端的應用有java applet,不過使用得很少,Java在伺服器端的應用非常的豐富,比如Servlet,JSP和第三方框架等等。Java技術對Web領域的發展注入了強大的動力。Java web 開發Java web開發學習路線一:入門階段學習目標:Java程式設計師1: 熟悉jdk,jvm,eclipse,安裝於配置jdk2:熟悉並掌握java的基礎語法,類,抽象類,接口,內部類等概念3: java核心編程,如輸入輸出流,多線程,集合,XML
  • JAVA8 新特性詳解
    如下圖所示,實現類報錯,實現類要求必須指定他要實現那個接口中的default方法結論3:如果一個類實現了多個接口,且這些接口中無繼承關係,這些接口中若有相同的(同名,同參數)的default方法,則接口實現類會報錯,接口實現類必須通過特殊語法指定該實現類要實現那個接口的default方法
  • Java閉包
    在這篇文章中,我們將粗略的看一遍Java8的特性,並介紹Lambda表達式。而且我將試著放一些樣例程序來解釋一些概念和語法。Java 程式語言給我們提供了接口的概念,接口裡可以定義抽象的方法。接口定義了 API,並希望用戶或者供應商來實現這些方法。很多時候,我們並不為一些接口創建獨立的實現類,我們通過寫一個匿名內部類來寫一個內聯的接口實現。匿名類使用的非常廣泛。