正則表達式
- 為什么要學習正則表達式
- 再提幾個問題
- 解決之道-正則表達式
- 正則表達式基本介紹
- 介紹
- 正則表達式底層實現
- 實例分析
- 正則表達式語法
- 基本介紹
- 元字符-轉義號 \\\\
- 元字符-字符匹配符
- 元字符-選擇匹配符
- 元字符-限定符
- 元字符-定位符
- 分組
- 非貪婪匹配
- 應用實例
- 對字符串進行如下驗證
- 正則表達式三個常用類
- 分組, 捕獲, 反向引用
- 提出需求
- 介紹
- 看幾個小案例
- 經典的結巴程序
- String類中使用正則表達式
- 替換功能
- 判斷功能
- 分割功能
- 本章作業
為什么要學習正則表達式
1.新建java項目chapter27
2.新建E:\idea_project\zzw_javase\idea_java_project\chapter27\src\com\zzw\regexp\Regexp_.java
public class Regexp_ {public static void main(String[] args) {String content = "私有地址(Private address)屬于非注冊地址,專門為組織機構內部使用。\n" +"以下列出留用的內部私有地址\n" +"A類 10.0.0.0--10.255.255.255\n" +"B類 172.16.0.0--172.31.255.255\n" +"C類 192.168.0.0--192.168.255.255";//1.先創建一個Pattern對象(模式對象), 可以理解成就是一個正則表達式對象//(1)提取文章中所有的英文單詞 -> 傳統方法, 使用遍歷, 代碼量大Pattern pattern = Pattern.compile("[a-zA-Z]+");//(2)提取文章中所有的數字//Pattern pattern = Pattern.compile("[0-9]+");//(3)提取文章中所有的英文單詞和數字//Pattern pattern = Pattern.compile("[a-zA-Z0-9]+");//2.創建一個匹配器對象// matcher 匹配器按照 pattern(模式/樣式) 到content中去查找/匹配Matcher matcher = pattern.matcher(content);//3.開始循環匹配while (matcher.find()) {//匹配內容/文本, 放到matcher.group(0)System.out.println("找到: " + matcher.group(0));}}
}
3.結論:正則表達式是處理文本的利器.
再提幾個問題
1.給你一個字符串(或文章), 請你找你所有四個數字連在一起的子串?
2.給你一個字符串(或文章), 請你找出所有四個數字連在一起的子串, 并且這四個數字要滿足: 第一位與第四位相同, 第二位與第三位相同. 比如: 1221, 3443.
3.請驗證輸入的郵件, 是否符合電子郵件格式.
4.請驗證輸入的手機號, 是否符合手機號格式.
解決之道-正則表達式
1.為了解決上述問題, Java提供了正則表達式技術, 專門用于處理類似文本問題.
2.簡單地說: 正則表達式是對字符串執行模式匹配的技術.
3.正則表達式: regular expression => RegExp
正則表達式基本介紹
介紹
1.一個正則表達式, 就使用某種模式去匹配字符串的一個公式. 很多人認為它們看上去比較古怪而且復雜所以不敢去使用. 不過, 經過練習后, 就覺得這些復雜的表達式寫起來還是相當簡單的, 而且, 一旦你弄懂它們, 你就能把數小時辛苦而且易錯的文本處理工作縮短在幾分鐘(甚至幾秒鐘)內完成.
2.這里特別強調, 正則表達式不是只有java才有, 實際上很多編程語言都支持正則表達式進行字符串操作!
正則表達式底層實現
實例分析
需求: 為了讓大家對正則表達式底層實現有一個直觀的印象, 給大家舉個實例. 給你一段字符串(文本), 請找出所有四個數字連在一起的子串. 比如, 應該找到 2000, 1998, 2012, 2020.
分析底層實現
1.新建src/com/zzw/regexp/RegTheory.java
//分析java正則表達式的底層實現
public class RegTheory {public static void main(String[] args) {String content = "1998 年 12 月 8 日,第二代 Java 平臺的企業版 J2EE 發布。1999 年 6 月,Sun 公司發布了\" +\n" +"\"第二代 Java 平臺(簡稱為 Java2)的 3 個版本:J2ME(Java2 Micro Edition,Java2 平臺的微型\" +\n" +"\"版),應用于移動、無線及有限資源的環境;J2SE(Java 2 Standard Edition,Java 2 平臺的\" +\n" +"\"標準版),應用于桌面環境;J2EE(Java 2Enterprise Edition,Java 2 平臺的企業版),應\" +\n" +"\"用 3443 于基于 Java 的應用服務器。Java 2 平臺的發布,是 Java 發展過程中最重要的一個\" +\n" +"\"里程碑,標志著 Java 的應用開始普及 9889 \"";//目標: 匹配所有四個數字//說明//1. \\d表示一個任意的數字String regStr = "(\\d\\d)(\\d\\d)";//2. 創建模式對象[即正則表達式對象]Pattern pattern = Pattern.compile(regStr);//3. 創建匹配器//說明: 創建匹配器 matcher, 按照正則表達式的規則 去匹配 content 字符串Matcher matcher = pattern.matcher(content);//4. 開始循環匹配/*** matcher.find() 完成的任務(這里考慮分組)* 什么是分組, 比如 (\d\d)(\d\d), 正則表達式中有()表示分組, 第1個()表示第1組, 第2個()表示第2組...* 1.根據指定的規則, 定位滿足規則的子字符串(比如(19)(98))* 2.找到后, 將子字符串的開始與結束的索引, 記錄到 matcher 對象的屬性 int[] groups;* (1) groups[0] = 0, 把該子字符串(1998)結束的索引+1 的值記錄到 groups[1] = 4* (2) 記錄第1組()匹配到的字符串 groups[2] = 0, gourps[3] = 2* (3) 記錄第2組()匹配到的字符串 groups[4] = 2, groups[5] = 4* (4) 如果有更多的分組...* 3.同時記錄oldLast的值為 子字符串的結束的索引+1的值, 即 4, 即下次執行find時, 就從 4 開始匹配** matcher.group(0)分析* 源碼:* public String group(int group) {* if (first < 0)* throw new IllegalStateException("No match found");* if (group < 0 || group > groupCount())* throw new IndexOutOfBoundsException("No group " + group);* if ((groups[group*2] == -1) || (groups[group*2+1] == -1))* return null;* return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();* }* 1.根據groups[0]=0 和 groups[1]=4 記錄的位置, 從content開始到截取子字符串返回* , 就是[0,4) 包含0但是不包含索引為35的位置** 2.如果再次指向 find 方法, 仍然按上面分析來執行*/while (matcher.find()) {/*** 小結* 1.如果正則表達式有(), 即分組* 2.去除匹配的字符串規則如下* (1)group(0) 表示匹配到的子字符串* (2)group(1) 表示匹配到的子字符串的第一組子串* (3)group(2) 表示匹配到的子字符串的第二組子串* (4)分組的數不能越界...*/System.out.println("找到: " + matcher.group(0));System.out.println("第1組()匹配到的值=" + matcher.group(1));System.out.println("第2組()匹配到的值=" + matcher.group(2));}}
}
正則表達式語法
基本介紹
如果要想靈活地運用正則表達式,必須了解其中各種元字符的功能,元字符從功能上大致分為:
1.限定符
2.選擇匹配符
3.分組組合和反向引用符
4.特殊字符
5.字符匹配符
6.定位符
元字符-轉義號 \\
\\ 符號 說明: 在我們使用正則表達式去檢索某些特殊字符的時候,需要用到轉義符號, 否則檢索不到結果,甚至會報錯的。
案例:用 $ 去匹配 “abc$(” 會怎樣?
提示: 在Java正則表達式中, 兩個 \\ 代表其它語言中的一個 \
1.新建src/com/zzw/regexp/RegExp02.java
//演示轉義字符的使用
public class RegExp02 {public static void main(String[] args) {String content = "abc$(a.bc(123( )";//匹配 ( => \\(//String regStr = "\\(";//匹配 . => \\.//String regStr = "\\.";//匹配 3個數字 => \\d\\d\\d//String regStr = "\\d\\d\\d";String regStr = "\\d{3}";Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);while (matcher.find()) {System.out.println("找到: " + matcher.group(0));}}
}
2.需要用到轉移符號的字符有以下: . * + ( ) $ / \ ?[ ] ^ { }
元字符-字符匹配符
符號 | 含義 | 示例 | 解釋 |
---|---|---|---|
[ ] | 可接收的字符列表 | [abcd] | a、b、c、d中的任意一個字符 |
[ ^ ] | 不可接收的字符列表 | [^abcd] | 除a、b、c、d外的任意一個字符(包括數字和特殊符號) |
- | 連字符 | A-Z | 任意單個大寫字母 |
符號 | 含義 | 示例 | 解釋 | 匹配輸入 |
---|---|---|---|---|
. | 匹配除 \n 以外的任何字符 | a..b | 以a開頭,b結尾,中間包括2個 任意字符的長度為4的字符串 | accb, a22b, a$#b |
\\d | 匹配單個數字字符, 相當于[0-9] | \d{3}(\d)? | 包含3個或4個數字的字符串 | 123,1234 |
\\D | 匹配單個非數字字符, 相當于[^0-9] | \\D(\\d)* | 以單個非數字字符開頭,后接 任意個數字字符串 | e1231, E332 |
\\w | 匹配單個數字, 大小寫字母字符,相當于[0-9a-zA-Z] | \d{3}\w{4} | 以3個數字字符開頭的 長度為7的數字字符串 | 123qwer, 12345qw |
\\W | 匹配單個非數字,大小寫字母字符,相當于[^0-9a-zA-Z] | \\W+\\d{2} | 以至少一個非數字字母開頭,2個 數字字符結尾的字符串 | #12, #$#@32 |
1.新建src/com/zzw/regexp/RegExp03.java
//演示字符匹配符的使用
public class RegExp03 {public static void main(String[] args) {String content = "a11c8abc _ABCy @";//String regStr = "[a-z]";//匹配a-z之間任意一個字符//String regStr = "[A-Z]";//匹配A-Z之間任意一個字符//String regStr = "abc";//匹配abc字符串[默認區分大小寫]//(?i) 是一個模式修飾符,表示不區分大小寫(ignore case)//String regStr = "(?i)abc";//匹配abc字符串[不區分大小寫]//String regStr = "[0-9]";//匹配0-9之間任意一個字符//String regStr = "[^a-z]";//匹配不在a-z之間任意一個字符//String regStr = "[^0-9]";//匹配不在0-9之間任意一個字符//String regStr = "[abcd]";//匹配abcd中任意一個字符//String regStr = "\\D";//匹配不在0-9的任意一個字符//String regStr = "\\w";//匹配一個大小寫英文字母,數字,下劃線//String regStr = "\\W";//匹配,等價于[^0-9a-zA-Z]//String regStr = "\\s";//\\s 匹配任何空白字符(空格,制表符等)//String regStr = "\\S";//\\S 匹配任何非空白字符,和\\s相反String regStr = ".";// . 匹配除\n之外的所有單個字符, 如果要匹配本身則使用\\.//注意: 當創建Pattern對象時, 指定 Pattern.Pattern pattern = Pattern.compile(regStr, Pattern.CASE_INSENSITIVE);Matcher matcher = pattern.matcher(content);while (matcher.find()) {System.out.println("找到: " + matcher.group(0));}}
}
注意:
String regStr = "."只會匹配一個字符
String regStr = ".*"則會匹配任意個字符
元字符-選擇匹配符
在匹配某個字符串的時候是選擇性的,即:即可以匹配這個,有可以匹配那個,這時需要使用到 選擇匹配符號 |
1.新建src/com/zzw/regexp/RegExp04.java
//演示選擇匹配符的使用
public class RegExp04 {public static void main(String[] args) {String content = "abcde趙志偉love趙培竹";String regStr = "趙|偉|培|竹";Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);while (matcher.find()) {System.out.println("找到: " + matcher.group(0));}}
}
輸出
找到: 趙
找到: 偉
找到: 趙
找到: 培
找到: 竹
元字符-限定符
用于指定其前面的字符和組合連續出現多少次
符號 | 含義 | 示例 | 解釋 | 匹配輸入 |
---|---|---|---|---|
* | 指定字符重復0次或n次(無要求,零到多) | (abc)* | 僅包含任意個abc的字符串, 等效于\w* | abc, abcabca |
+ | 指定字符重復1次或n次(至少一次, 一到多) | m+(abc)* | 以至少一個m開頭, 后接 任意個abc的字符串 | m,mabc,mabcabc |
? | 指定字符重復0次或1次(最多一次, 零到一) | m+abc? | 以至少一個m開頭, 后接ab或abc的字符串 | mab, mabc,mmab, mmabc |
{n} | 只能輸入n個字符 | [abcd]{3} | 由abcd中任意字母組成的 長度為3的字符串 | aac, dbc, adc |
{n,} | 至少指定n個匹配 | [abcd]{3,} | 由abcd中任意字母組成的 長度不小于3的字符串 | aab, dbc, abcada |
{n,m} | 指定至少n個但不多于m個匹配 | [abcd]{3,5} | 由abcd中任意字母組成的長度 不小于3,不大于5的字符串 | abc, abcd, abaaa, bbbbb |
1.新建src/com/zzw/regexp/RegExp05.java
//演示限定符的使用
public class RegExp05 {public static void main(String[] args) {String content = "a211111aaaaaahello";//String regStr = "a{3}";//匹配 aaa//String regStr = "1{4}";//匹配 1111//String regStr = "\\d{2}";//匹配 兩位任意數字字符//細節: java匹配默認是貪婪匹配, 即盡可能匹配多的//String regStr = "a{3,4}";//表示匹配 aaa或者aaaa//String regStr = "1{4,5}";//表示匹配 1111或11111//String regStr = "\\d{2,5}";//表示匹配 兩位任意數字字符 或者三位,四位,五位//String regStr = "1+";//表示匹配1個或多個1//String regStr = "\\d+";//表示匹配一個數字或多個數字//String regStr = "1*";//表示匹配0個或多個1//演示?的使用, 遵守貪婪匹配String regStr = "a1?";//匹配 a或者a1Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);while (matcher.find()) {System.out.println("找到: " + matcher.group(0));}}
}
元字符-定位符
定位符, 規定要匹配的字符串出現的位置, 比如在字符串的開始還是在結束的位置, 必須掌握.
符號 | 含義 | 示例 | 解釋 | 匹配輸入 |
---|---|---|---|---|
^ | 指定起始字符 | ^[0-9]+[a-z]* | 以至少一個數字開頭, 后接 任意個小寫字符的字符串 | 123,6aa,555edf |
$ | 指定結束字符 | ^[0-9]\-[a-z]+$ | 以一個數字開頭后接連字符"=" 并以至少一個小寫字母結尾的字符串 | 1-a |
\\b | 匹配目標字符串的邊界 | wei\\b | 這里說的字符串的邊界指的是子串間有空格 或者是目標字符串的結束位置 | |
\\B | 匹配目標字符串的非邊界 | wei\\B | 和\\b的含義正好相反 |
1.新建`src/com/zzw/regexp/RegExp06.java`
//演示定位符的使用
public class RegExp06 {public static void main(String[] args) {String content = "hanshunping sphan nnhan";//String content = "123-abc";//以至少一個數字字符開頭, 后接任意個小寫字母//String regStr = "^[0-9]+[a-z]*$";//以至少一個數字字符開頭, 以至少一個小寫字母結束(體現了貪婪匹配)//String regStr = "^[0-9]+\\-[a-z]+$";//表示匹配邊界的han// (這里的邊界是指: 被匹配的字符串最后, 也可以是空格的子字符串的最后)/*找到: han找到: han*///String regStr = "han\\b";//和\\b的含義剛剛相反/*找到: han找到: han*/String regStr = "\\Bhan";Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);while (matcher.find()) {System.out.println("找到: " + matcher.group(0));}}
}
分組
常用分組構造形式 | 說明 |
---|---|
(pattern) | 非命名捕獲. 捕獲匹配的子字符串. 編號為零的第一個捕獲是由整個正則表達式模式匹配的文本. 其它捕獲結果則根據左括號的順序從1開始自動編號. |
(?<name>pattern) | 命名捕獲, 將匹配的子字符串捕獲到一個組名稱或編號名稱中. 用于name的字符串 不能包含任何標點符號, 并且不能以數字開頭, 可以使用單引號替代尖括號. 例如 (?‘name’) |
(?:pattern) | 匹配 pattern 但不捕獲該匹配的子表達式, 即它是一個非捕獲匹配, 不存儲供以后使用的匹配. 這對于用"or"字符 (|) 組合模式部件的情況很有用. 例如: 'industr(?:y|ies) 是比 industry|industries更經濟的表達式. |
(?=pattern) | 它是一個非捕獲匹配. 例如: Windows (?=95|98|NT|2000) 匹配 Windows 2000 中的 Windows, 但不匹配 Windows 3.1 中的 Windows |
(?!pattern) | 該表達式匹配不處于匹配 pattern 的字符串的起始點的搜索字符串. 它是一個非捕獲匹配. 例如, Windows (?!95|98|NT|2000) 匹配 Windows 3.1 中的 Windows, 但不匹配 Windows 2000 中的 Windows |
1.新建src/com/zzw/regexp/RegExp07.java
public class RegExp07 {public static void main(String[] args) {String content = "zhaozhiwei s2012 nihao1015zhao";//下面就是非命名分組//說明//1. matcher.group(0) 得到匹配到的字符串//2. matcher.group(1) 得到匹配到的字符串的第1個分組內容//3. matcher.group(2) 得到匹配到的字符串的第2個分組內容//String regStr = "(\\d\\d)(\\d\\d)";//匹配4個數字的字符串//命名分組: 即可以給分組取名String regStr = "(?<g1>\\d\\d)(?<g2>\\d\\d)";Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);while (matcher.find()) {System.out.println("找到: " + matcher.group(0));System.out.println("第1個分組內容: " + matcher.group(1));System.out.println("第2個分組內容: " + matcher.group(2));System.out.println("第一個分組內容[通過組名]: " + matcher.group("g1"));System.out.println("第二個分組內容[通過組名]: " + matcher.group("g2"));}}
}
2.新建src/com/zzw/regexp/RegExp08.java
//演示非捕獲分組, 語法比較奇怪
public class RegExp08 {public static void main(String[] args) {String content = "hello 周杰倫歌手 hello 周杰倫導演 hello 周杰倫老師 hello 周杰倫演員 hello 周杰倫baby";//找到: 周杰倫歌手, 周杰倫導演, 周杰倫老師, 周杰倫演員, 周杰倫baby//String regStr = "周杰倫歌手|周杰倫導演|周杰倫老師周杰倫演員|周杰倫baby";//下面的寫法可以等價非捕獲分組. 注意: 不能 matcher.group(1)//String regStr = "周杰倫(?:歌手|導演|老師|演員|baby)";//找到 周杰倫 這個關鍵詞, 但是要求只是查找周杰倫歌手, 周杰倫演員 中包含的周杰倫//下面也是非捕獲分組, 不能使用 matcher.group(1)//String regStr = "周杰倫(?=歌手|演員)";//找到 周杰倫 這個關鍵詞, 但是要求只是查找 不是 (周杰倫歌手 和 周杰倫演員) 中包含的周杰倫//下面也是非捕獲分組, 不能使用 matcher.group(1)String regStr = "周杰倫(?!歌手|演員)";Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);while (matcher.find()) {System.out.println("找到: " + matcher.group(0));}}
}
非貪婪匹配
1.新建com.zzw.regexp.RegExp09.java
public class RegExp09 {public static void main(String[] args) {String content = "hello1111111 ok";//String regStr = "\\d+";//默認是貪婪匹配String regStr = "\\d+?";//非貪婪匹配Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);while (matcher.find()) {System.out.println("找到: " + matcher.group(0));}}
}
應用實例
對字符串進行如下驗證
1.漢字
2.郵政編碼. 要求: 是1-9開頭的一個六位數. 比如:123890
3.QQ號碼. 要求:是1-9開頭的一個(5位數-10位數) 比如: 12345, 123456789, 978964140
4.手機號碼. 要求: 必須以13, 14, 15, 18開頭的11位數, 比如 13031758275
5.URL : 比如
https://www.bilibili.com/video/BV16Z4y1i7vv/?p=7&spm_id_from=pageDriver&vd_source=03325a87946ce23102fa48daa830127a
新建com.zzw.regexp.RegExp10.java
//正則表達式應用實例
public class RegExp10 {public static void main(String[] args) {//漢字//String content = "趙志偉";//String regStr = "^[\\u0391-\\uffe5]+$";//郵政編碼//要求: 是1-9開頭的一個六位數. 比如:123890//String content = "123890";//String regStr = "^[1-9]\\d{5}$";//QQ號碼//要求:是1-9開頭的一個(5位數-10位數) 比如: 12345, 123456789, 978964140//String content = "978964140";//String regStr = "^[1-9]\\d{4,9}$";//手機號碼//要求: 必須以13, 14, 15, 18開頭的11位數, 比如 13031758275String content = "13031758275";String regStr = "^(?:13|14|15|18)\\d{9}$";Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);if (matcher.find()) { System.out.println("滿足格式"); } else { System.out.println("不滿足格式"); }}
}
新建com.zzw.regexp.RegExp11.java
//正則表達式應用實例
public class RegExp11 {public static void main(String[] args) {String content = "https://www.bilibili.com/video/BV16Z4y1i7vv/?p=7&spm_id_from=pageDriver&vd_source=03325a87946ce23102fa48daa830127a";/*** 思路* 1.先確定 url 的開始部分 http(?:s|)://* 2.然后通過 ([\\w-]+\.)+[\\w-]+, 匹配 www.bilibili.com* 3.通過 (\\/[\\w-?=&/%.#]*)? 匹配 /video/BV16Z4y1i7vv/?p=7&spm_id_from=pageDriver&vd_source=03325a87946ce23102fa48daa830127a*/String regStr = "(http(?:s|)://)?([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?";Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);while (matcher.find()) {System.out.println("找到: " + matcher.group(0));}//這里如果使用 Pattern 的 matcheres 整體匹配 比較簡潔 System.out.println(Pattern.matches(regStr, content));}
}
正則表達式三個常用類
java.util.regex
包主要包括以下三個類 Patterh
類, Matcher
類 和 PatternSyntaxException
.
●Pattern類
Pattern
對象是一個正則表達式對象. Pattern
類沒有公共構造方法, 要創建一個 Pattern
對象, 需調用其公共靜態方法, 返回一個 Pattern
對象. 該方法接受一個正則表達式作為它的第一個參數. 比如:Pattern pattern = Pattern.compile(regStr)
●Matcher類
Matcher
對象是對輸入字符串進行解釋和匹配的引用. 與Pattern
類一樣, Matcher
也沒有公共構造方法, 需要調用 Pattern
對象的matcher
方法來獲一個Matcher
對象.
●PatternSyntaxException
PatternSyntaxException
是一個非強制異常類, 它表示一個正則表達式模式中的語法錯誤.
1.新建com.zzw.regexp.PatternMethod.java
//演示 matches 方法, 用于整體匹配, 在驗證輸入的字符串是否滿足條件時使用
public class PatternMethod {public static void main(String[] args) {String content = "hello world 趙志偉 虛擬世界";//String regStr = "hello";String regStr = "hello.*";boolean matches = Pattern.matches(regStr, content);System.out.println("整體匹配: " + matches);}
}
2.新建com.zzw.regexp.MatcherMethod.java
//Matcher類的常用方法
public class MatcherMethod {public static void main(String[] args) {String content = "hello tom hello jack hello king hello queen";String regStr = "hello";Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);while (matcher.find()) {System.out.println("==================");System.out.println(matcher.start());System.out.println(matcher.end());System.out.println("找到: " + content.substring(matcher.start(), matcher.end()));}//整體匹配方法, 常用于 去校驗某個字符串是否滿足某個規則System.out.println("整體匹配: " + matcher.matches());//完成如果 content 有 king 替換成 國王regStr = "king";pattern = Pattern.compile(regStr);matcher = pattern.matcher(content);//注意: 返回的字符串才是替換后的字符串, 原來的 content 不變化String newContent = matcher.replaceAll("國王");System.out.println("替換后的字符串: " + newContent);System.out.println("content: " + content);}
}
分組, 捕獲, 反向引用
提出需求
請看下面問題:
給你一段文本, 請你找出四個數字連在一起的字串, 并且這四個數字要滿足第1位與第4位相同, 第2位與第3位相同, 比如 1221, 5775…
介紹
(\\d\\d)(\\d\\d)
要滿足前面的問題, 我們需要了解正則表達式的幾個概念
1.分組
我們可以用圓括號組成一個比較復雜的匹配模式, 那么一個圓括號的部分我們看作是一個子表達式/一個分組.
2.捕獲
把正則表達式中子表達式/分組匹配的內容, 保存到內存中以數字編號或顯示命名的組里, 方便后面引用. 從左向右, 以分組的左括號為標志, 第一個出現的分組的組號為1, 第二個為2, 依此類推, 組0代表的是整個正則式.
3.反向引用
圓括號的內容被捕獲后, 可以在這個括號后被使用, 從而寫出一個比較實用的匹配模式, 這個我們稱為反向引用, 這種引用既可以使在正則表達式內部, 也可以是在正則表達式外部, 內部反向引用 \分組號, 外部反向引用 $分組號.
看幾個小案例
1.要匹配兩個連續的相同數字: (\\d)\\1
2.要匹配五個連續的相同數字: (\\d)\\1{4}
3.要匹配個位與千位相同, 十位與百位相同的數 (\\d)(\\d)\\2\\1
●思考題
請在字符串中檢索商品編號, 形式如: 12321-333999111 這樣的號碼, 要求滿足前面是一個五位數, 然后一個-號, 然后是一個九位數, 連續的每三位要相同.
1.新建com.zzw.regexp.RegExp12.java
public class RegExp12 {public static void main(String[] args) {String content = "1232112321-333666999321412";String regStr = "\\d{5}\\-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}";Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);while (matcher.find()) {System.out.println("找到: " + matcher.group(0));}}
}
經典的結巴程序
把類似 “我…我要…學學學學…編程java!” 通過正則表達式 修改成 “我要學編程java!”
1.新建com.zzw.regexp.RegExp13.java
public class RegExp13 {public static void main(String[] args) {String content = "我....我要....學學學學....編程java!";//1.去掉所有的 .String regStr = "\\.";Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);String newContent = matcher.replaceAll("");System.out.println("newContent=" + newContent);//2.去掉連續重復的字regStr = "(.)\\1+";pattern = Pattern.compile(regStr);matcher = pattern.matcher(newContent);newContent = matcher.replaceAll("$1");System.out.println("newContent=" + newContent);}
}
String類中使用正則表達式
替換功能
public String replaceAll(String regex, String replacement)
判斷功能
public boolean matches(String regex) 使用 Pattern 和 Matcher 類
分割功能
public String[] split(String regex)
1.新建com.zzw.regexp.StringReg.java
public class StringReg {public static void main(String[] args) {//使用正則表達式, 將 jdk1.3 和 jdk1.4 替換成 jdkString content = "馬踏飛燕jdk1.3 hello,worldjdk1.4 hello";String regStr = "jdk1\\.(?:3|4)";String newContent = content.replaceAll(regStr, "jdk");System.out.println("newContent=" + newContent);//要求: 驗證一個手機號, 要求必須使以 138 139 開頭的content = "13812345678";if (content.matches("^13(?:8|9)\\d{8}$")) {System.out.println("驗證成功");} else {System.out.println("驗證失敗");}//要求: 按照 # 或者 - 或者 ~ 或者 數字 來分割字符串content = "趙志偉#山東省-濟寧市~泗水縣33泗張鎮~付山莊村";String[] split = content.split("#|-|~|\\d+");for (String string : split) {System.out.println(string);}}
}
本章作業
1.驗證電子郵件格式是否合法. 規定電子郵件規則是
①只能有一個@
②@前面是用戶名, 可以是a-z A-Z 0-9 _ - 字符
③@后面是域名, 并且域名只能是英文字母, 比如 sohu.com 或者 tsinghua.org.cn
④寫出對應的正則表達式, 驗證輸入的字符串是否滿足規則
新建com.zzw.homework.Homework01.java
public class Homework01 {public static void main(String[] args) {String content = "978964140@qq.com";String regStr = "[\\w_-]+@([a-zA-Z]+\\.)+[a-zA-Z]+";if (content.matches(regStr)) {System.out.println("符合要求");} else {System.out.println("不符合要求");}}
}
2.要求驗證是不是整數或者小數. 提示: 這個題要考慮整數和負數.
比如: 123, -123, 34.53, -21.54, 0.99, -0.43 等.
新建com.zzw.homework.Homework02.java
public class Homework02 {public static void main(String[] args) {String content = "-0.12";//判斷是不是整數String regStr = "^(?:|\\+|-)[1-9]\\d*$";if (content.matches(regStr)) {System.out.println("是整數");} else {System.out.println("不是整數");}//判斷是不是小數regStr = "^(?:|\\+|-)\\d+\\.\\d+$";if (content.matches(regStr)) {System.out.println("是小數");} else {System.out.println("不是小數");}//判斷是不是整數或小數regStr = "^[+-]?([1-9]\\d*|0)(\\.\\d+)?$";if (content.matches(regStr)) {System.out.println("是整數或小數");} else {System.out.println("不是整數或小數");}
}
3.對一個url進行解析
http://www.bilibili.com:8080/abc/index.html
①要求得到協議是什么? http
②域名是什么? www.sohu.com
③端口是什么? 8080
④文件名是什么? index.html
新建com.zzw.homework.Homework03.java
public class Homework03 {public static void main(String[] args) {String content = "http://www.bilibili.com:8080/abc/index.html";String regStr = "^((?<g1>http(?:s|))://)?(?<g2>([\\w-]+\\.)+[\\w-]+):(?<g3>\\d+)/\\w+/(?<g4>([\\w-]+\\.)+[\\w-]+)$";Pattern pattern = Pattern.compile(regStr);Matcher matcher = pattern.matcher(content);while (matcher.find()) {System.out.println("找到: " + matcher.group("g1"));System.out.println("找到: " + matcher.group("g2"));System.out.println("找到: " + matcher.group("g3"));System.out.println("找到: " + matcher.group("g4"));}}
}