Java正則表達式入門學習與實踐

Java正則表達式入門學習與實踐

  • 一、正則基礎知識點
    • 1、元字符
    • 2、重復限定符
    • 3、分組
    • 4、轉義
    • 5、條件或
    • 6、區間
  • 二、正則進階知識點
    • 1、零寬斷言
    • 2、零寬斷言測試
    • 3、捕獲和非捕獲
    • 3、反向引用
  • 三、貪婪和非貪婪
    • 1、貪婪
    • 2、懶惰(非貪婪)
  • 四、反義
  • 五、 案例
    • 1、匹配時間

一、正則基礎知識點

1、元字符

元字符說明
.匹配除換行符以外的任意字符
\w匹配字母或數字或下劃線或漢字
\s匹配任意的空白符
\d匹配數字
\b匹配單詞的開始或結束
^匹配字符串的開始
$匹配字符串的結束

元字符案例
匹配有abc開頭的字符串

\babc或者^abc

匹配8位數字的QQ號碼

^\d\d\d\d\d\d\d\d$

匹配1開頭11位數字的手機號碼

^1\d\d\d\d\d\d\d\d\d\d$

2、重復限定符

語法說明
*重復零次或更多次
+重復一次或更多次
?重復零次或一次
{n}重復n次
{n,}重復n次或更多次
{n,m}重復n到m次

重復限定符案例
匹配8位數字的QQ號碼

在這里插入代碼片

匹配1開頭11位數字的手機號碼

^1\d{10}$

匹配銀行卡號是14~18位的數字

^\d{14,18}$

匹配以a開頭的,0個或多個b結尾的字符串

^ab*$

3、分組

匹配字符串中包含0到多個ab開頭

^(ab)*

4、轉義

如果要匹配的字符串中本身就包含小括號,那是不是沖突?應該怎么辦?

針對這種情況,正則提供了轉義的方式,也就是要把這些元字符、限定符或者關鍵字轉義成普通的字符,做法很簡答,就是在要轉義的字符前面加個斜杠,也就是\即可。
如:要匹配以(ab)開頭

^(\(ab\))*

5、條件或

正則用符號 | 來表示或,也叫做分支條件,當滿足正則里的分支條件的任何一種條件時,都會當成是匹配成功。

^(130|131|132|155|156|185|186|145|176)\d{8}$

6、區間

正則提供一個元字符中括號 [] 來表示區間條件。

  1. 限定0到9 可以寫成[0-9]
  2. 限定A-Z 寫成[A-Z]
  3. 限定某些數字 [165]

那上面的正則我們還改成這樣

^((13[0-2])|(15[56])|(18[5-6])|145|176)\d{8}$

二、正則進階知識點

1、零寬斷言

語法說明
(expr)捕獲 expr 子模式,以 \1 使用它。
(?:expr)忽略捕獲的子模式。
(?=expr)正向預查模式 expr。
(?!expr)負向預查模式 expr。

(?=pattern)
正向肯定預查(look ahead positive assert),匹配pattern前面的位置。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。

簡單說,以 xxx(?=pattern)為例,就是捕獲以pattern結尾的內容xxx

例如,“Windows(?=95|98|NT|2000)“能匹配"Windows2000"中的"Windows”,但不能匹配"Windows3.1"中的"Windows”。預查不消耗字符,也就是說,在一個匹配發生后,在最后一次匹配之后立即開始下一次匹配的搜索,而不是從包含預查的字符之后開始。

(?!pattern)
正向否定預查(negative assert),在任何不匹配pattern的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。

簡單說,以 xxx(?!pattern)為例,就是捕獲不以pattern結尾的內容xxx

例如"Windows(?!95|98|NT|2000)“能匹配"Windows3.1"中的"Windows”,但不能匹配"Windows2000"中的"Windows"。預查不消耗字符,也就是說,在一個匹配發生后,在最后一次匹配之后立即開始下一次匹配的搜索,而不是從包含預查的字符之后開始。

(?<=pattern)
反向(look behind)肯定預查,與正向肯定預查類似,只是方向相反。

簡單說,以(?<=pattern)xxx為例,就是捕獲以pattern開頭的內容xxx。

例如,"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。

(?<!pattern)
簡單說,以(?<!pattern)xxx為例,就是捕獲不以pattern開頭的內容xxx。

反向否定預查,與正向否定預查類似,只是方向相反。例如"(?<!95|98|NT|2000)Windows"能匹配"3.1Windows"中的"Windows",但不能匹配"2000Windows"中的"Windows"。

2、零寬斷言測試

class DemoApplicationTests {void contextLoads() {//創建測試樣例String test = "abc123xyz";//創建正則表達式String reg1 = "\\w(?=123)";String reg2 = "\\w(?!123)";String reg3 = "(?<=abc)\\w";String reg4 = "(?<!abc)23";Pattern pattern1 = Pattern.compile(reg1);Pattern pattern2 = Pattern.compile(reg2);Pattern pattern3 = Pattern.compile(reg3);Pattern pattern4 = Pattern.compile(reg4);//查找Matcher mc1 = pattern1.matcher(test);Matcher mc2 = pattern2.matcher(test);Matcher mc3 = pattern3.matcher(test);Matcher mc4 = pattern4.matcher(test);if (mc1.find()) {System.out.println(mc1.group());}if (mc2.find()) {System.out.println(mc2.group());}if (mc3.find()) {System.out.println(mc3.group());}if (mc4.find()) {System.out.println(mc4.group());}}
}

在這里插入圖片描述

3、捕獲和非捕獲

數字編號捕獲組
語法:(exp)解釋:從表達式左側開始,每出現一個左括號和它對應的右括號之間的內容為一個分組,在分組中,第0組為整個表達式,第一組開始為分組。
比如固定電話的:020-85653333
他的正則表達式為:(0\d{2})-(\d{8})
按照左括號的順序,這個表達式有如下分組:

序號編號分組內容
00(0\d{2})-(\d{8})020-85653333
11(0\d{2])020
22(\d{8})85653333
class DemoApplicationTests {@Testvoid contextLoads1() {String test = "020-85653333";String reg = "(0\\d{2})-(\\d{8})";Pattern pattern = Pattern.compile(reg);Matcher mc = pattern.matcher(test);if (mc.find()) {System.out.println("分組的個數有:" + mc.groupCount());for (int i = 0; i <= mc.groupCount(); i++) {System.out.println("第" + i + "個分組為:" + mc.group(i));}}}}

在這里插入圖片描述
可見,分組個數是2,但是因為第0個為整個表達式本身,因此也一起輸出了。

命名編號捕獲組
語法:(?exp)
解釋:分組的命名由表達式中的name指定
比如區號也可以這樣寫:(?\0\d{2})-(?\d{8})
按照左括號的順序,這個表達式有如下分組:

序號編號分組內容
00(0\d{2})-(\d{8})020-85653333
1quhao(0\d{2])020
2haoma(\d{8})85653333
class DemoApplicationTests {@Testvoid contextLoads1() {String test = "020-85653333";String reg = "(?<quhao>0\\d{2})-(?<haoma>\\d{8})";Pattern pattern = Pattern.compile(reg);Matcher mc = pattern.matcher(test);if (mc.find()) {System.out.println("分組的個數有:" + mc.groupCount());System.out.println(mc.group("quhao"));System.out.println(mc.group("haoma"));}}
}

在這里插入圖片描述

非捕獲組
語法:(?:exp)
(?:expr) 忽略捕獲的子模式。
解釋:和捕獲組剛好相反,它用來標識那些不需要捕獲的分組,說的通俗一點,就是你可以根據需要去保存你的分組。

序號編號分組內容
00(0\d{2})-(\d{8})020-85653333
1quhao(0\d{2])020

比如上面的正則表達式,程序不需要用到第一個分組,那就可以這樣寫:

class DemoApplicationTests {@Testvoid contextLoads1() {String test = "020-85653333";String reg = "(?:0\\d{2})-(\\d{8})";Pattern pattern = Pattern.compile(reg);Matcher mc = pattern.matcher(test);if (mc.find()) {System.out.println("分組的個數有:" + mc.groupCount());for (int i = 0; i <= mc.groupCount(); i++) {System.out.println("第" + i + "個分組為:" + mc.group(i));}}}
}

在這里插入圖片描述

3、反向引用

根據捕獲組的命名規則,反向引用可分為

  1. 數字編號組反向引用:\k或\number
  2. 命名編號組反向引用:\k或者’name’

反向引用如:\1,\2等
\1:表示的是引用第一次匹配到的()括起來的部分
\2:表示的是引用第二次匹配到的()括起來的部分

例:(\d)\1
首先這里是匹配兩位,\d一位,\1又引用\d一位 這里的\1會去引用(\d)匹配到的內容,因為(\d)是第一次匹配到的內容。
如:str = "22"時,(\d)匹配到2,所以\1引用(\d)的值也為2,所以str="22"能匹配
str = "23"時,(\d)匹配到2,因為\1引用(\d)的值2,而這里是3,所以str="23"不能匹配

例:(\d)\10-9\2{2}
這里使用了\2引用第二次匹配到的分組,這里第二次匹配的分組為\2前面的(\d),這里的{2}指的是\2的值出現兩次
如:第一個(\d)為4時,\1引用第1個(\d)也為4,第二個(\d)為5時,\2引用第二個(\d)為5,所以結果可以是:447555,440222

在這里插入圖片描述
例:(\d)\1[0-9](\d)\1{2}
注意在后面第二個(\d)\1{2}中的\1,這里的\1并不會去匹配他前面的(\d),而是匹配第一個(\d),
如:第一個(\d)為3時,則第一個\1也為3,同樣最后那個\1也為3,所以結果可以是335933,332533而不是336444,339888
在這里插入圖片描述

例:((\d)3)\1[0-9](\d)\2{2}
當匹配中的分組有嵌套時,是從外向里匹配的,其次在由左向右匹配
這里主要是分析匹配到分組的順序,首先匹配((\d)3)這整個部分,其次匹配((\d)3)里面的(\d),第三次匹配時最后一個\2前面的(\d)
如:如((\d)3)中的(\d)為2時,((\d)3)的值為23,此時\1為((\d)3)的值1,而\2引用((\d)3)中的(\d)的值3,第三個(\d)為5時,此時\3引用第三個(\d)的值5,所以結果可以有:23238522,23230522,

在這里插入圖片描述

三、貪婪和非貪婪

1、貪婪

貪婪匹配:當正則表達式中包含能接受重復的限定符時,通常的行為是(在使整個表達式能得到匹配的前提下)匹配盡可能多的字符,這匹配方式叫做貪婪匹配。特性:一次性讀入整個字符串進行匹配,每當不匹配就舍棄最右邊一個字符,繼續匹配,依次匹配和舍棄(這種匹配-舍棄的方式也叫做回溯),直到匹配成功或者把整個字符串舍棄完為止,因此它是一種最大化的數據返回,能多不會少。

用來匹配3到6位數字,在這種情況下,它是一種貪婪模式的匹配,也就是假如字符串里有6個個數字可以匹配,那它就是全部匹配到。

class DemoApplicationTests {void contextLoads3() {String reg = "\\d{3,6}";String test = "61762828 176 2991 871";System.out.println("文本:" + test);System.out.println("貪婪模式:" + reg);Pattern p1 = Pattern.compile(reg);Matcher m1 = p1.matcher(test);while (m1.find()) {System.out.println("匹配結果:" + m1.group(0));}}
}

在這里插入圖片描述

是這樣的,多個貪婪在一起時,如果字符串能滿足他們各自最大程度的匹配時,就互不干擾,但如果不能滿足時,會根據深度優先原則,也就是從左到右的每一個貪婪量詞,優先最大數量的滿足,剩余再分配下一個量詞匹配。

class DemoApplicationTests {@Testvoid contextLoads3() {String reg = "(\\d{1,2})(\\d{3,4})";String test = "61762828 176 2991 87321";System.out.println("文本:" + test);System.out.println("貪婪模式:" + reg);Pattern p1 = Pattern.compile(reg);Matcher m1 = p1.matcher(test);while (m1.find()) {System.out.println("匹配結果:" + m1.group(0));}}
}

在這里插入圖片描述

  1. “617628” 是前面的\d{1,2}匹配出了61,后面的匹配出了7628
  2. “2991” 是前面的\d{1,2}匹配出了29 ,后面的匹配出了91
  3. "87321"是前面的\d{1,2}匹配出了87,后面的匹配出了321

2、懶惰(非貪婪)

懶惰匹配:當正則表達式中包含能接受重復的限定符時,通常的行為是(在使整個表達式能得到匹配的前提下)匹配盡可能少的字符,這匹配方式叫做懶惰匹配。特性:從左到右,從字符串的最左邊開始匹配,每次試圖不讀入字符匹配,匹配成功,則完成匹配,否則讀入一個字符再匹配,依此循環(讀入字符、匹配)直到匹配成功或者把字符串的字符匹配完為止。

代碼說明
*?重復任意次,但盡可能少重復
+?重復1次或更多次,但盡可能少重復
??重復0次或1次,但盡可能少重復
{n,m}?重復n到m次,但盡可能少重復
{n,}?重復n次以上,但盡可能少重復
class DemoApplicationTests {void contextLoads3() {String reg = "(\\d{1,2}?)(\\d{3,4})";String test = "61762828 176 2991 87321";System.out.println("文本:" + test);System.out.println("貪婪模式:" + reg);Pattern p1 = Pattern.compile(reg);Matcher m1 = p1.matcher(test);while (m1.find()) {System.out.println("匹配結果:" + m1.group(0));}}
}

在這里插入圖片描述

解答
“61762” 是左邊的懶惰匹配出6,右邊的貪婪匹配出1762
“2991” 是左邊的懶惰匹配出2,右邊的貪婪匹配出991
“87321” 左邊的懶惰匹配出8,右邊的貪婪匹配出7321

四、反義

前面說到元字符的都是要匹配什么什么,當然如果你想反著來,不想匹配某些字符,正則也提供了一些常用的反義元字符:

元字符解釋
\w匹配任意不是字母,數字,下劃線,漢字的字符
\s匹配任意不是空白符的字符
\D匹配任意非數字的字符
\B匹配不是單詞開頭或結束的位置
[^x]匹配除了x以外的任意亨符
[^aeiou]匹配除了aeiou這幾個字母以外的任意字符

五、 案例

1、匹配時間

\d{4}?/?\d{1,2}?/?\d{1,2}?([ ]\d{1,2}:??\d{1,2}:??\d{1,2}?)?

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處:https://dhexx.cn/hk/18278.html

如若內容造成侵權/違法違規/事實不符,請聯系我的編程經驗分享網進行投訴反饋,一經查實,立即刪除!


相關文章:

  • Java:集合,Collection接口框架圖
  • Spark Streaming入門-編程入口JavaStreamingContext的實例化,構造方法匯總
  • IOS-synthesize和dynamic的異同(轉)
  • V8 API Reference Guide
  • Hadoop的內置的基本數據類型
  • Java中String的replace、replaceAll和replaceFirst方法
  • 【數據庫復習】第二章關系數據庫2
  • GhostDoc的使用
  • HDU 4870Rating(推公式)
  • spark常用RDD算子 - saveAsTextFile、saveAsObjectFile 可保存到本地文件或hdfs系統中
  • Linux服務器編輯jar包并重新運行與直接修改jar包
  • hdu 4686 Arc of Dream(矩陣快速冪)
  • 糾結的CLI C++與Native C++的交互
  • kafka概述,架構說明,相關的名詞解釋
  • JAVA基礎知識
  • 棧Stack和段寄存器SS,SP(學習匯編)
  • 【轉載】Linux下動態共享庫加載時的搜索路徑詳解
  • Linux下打包和解壓zip文件
  • kafka四大核心api
  • java List的用法
  • 抽象數據類型的表示與實現
  • kafka工作流程分析-生產過程
  • 事務隔離級別和MVCC的關系
  • Windows 下c獲取文件目錄
  • LeetCode--Max Points on a Line
  • kafka工作流程分析-Broker保存消息
  • MS SQL Server時間常用函數
  • ThreadLocal簡介
  • Repeater分頁
  • kafka工作流程分析-消費過程分析
  • 模仿易信的UI
  • java中volatile關鍵字的作用
  • 安裝VC6.0遇到的問題
  • 集群方式安裝kafka,集群啟動kafka,集群關閉kafka
  • 第六章 跑馬燈實驗
  • 查看安裝的kafka的版本的方法
  • WebService整合SpringBoot2.0
  • Linux線程學習(一)
  • Hue概述,核心功能,架構說明
  • java多線程技術
  • dubbo簡單了解
  • easyui時間格式問題
  • hdu 2485(最小費用最大流)
  • MySQL索引優化進階如聚集索引、輔助索引、覆蓋索引、聯合索引
  • 【Java】ArrayList和LinkedList的區別
  • hue通過tar.gz包的方式安裝,啟動
  • 和為指定值的連續序列
  • (轉載)MQ基本操作
  • 服務器配置MySQL主從復制搭建,一主多從
  • Hue?集成HDFS文件系統