介紹
為什么需要
? ? 正則表達式是處理文本的利器;
基本介紹
? ? 正則表達式,又稱規(guī)則表達式,(Regular Expression,在代碼中常簡寫為regex、regexp或RE)。它是一個強大的字符串處理工具,可以對字符串進行查找、提取、分割、替換等操作,是一種可以用于模式匹配和替換的規(guī)范;
? ? 一個正則表達式就是由普通的字符(如字符 a~z)以及特殊字符(元字符)組成的文字模式,用以描述在查找文字主體時待匹配的一個或多個字符串。
? ? jdk1.4推出?java.util.regex 包,它包含了 Pattern 和 Matcher 類,用于處理正則表達式的匹配操作。
package com.lhy.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 分析java的正則表達式的底層實現(xiàn)(重要.)
*/
public class RegTheory {
public static void main(String[] args) {
String content = "1998年12月8日,第二代Java平臺的企業(yè)版J2EE發(fā)布" ;
//目標:匹配所有四個數(shù)字
//說明
//1. \\d 表示一個任意的數(shù)字
String regStr = "(\\d\\d)(\\d\\d)";
//2. 創(chuàng)建一個模式對象[即正則表達式對象]
Pattern pattern = Pattern.compile(regStr);
//3. 創(chuàng)建一個匹配器對象
//說明:創(chuàng)建匹配器matcher, 按照 正則表達式的規(guī)則(pattern模式) 去匹配 content字符串
Matcher matcher = pattern.matcher(content);
//4.開始循環(huán)匹配
while (matcher.find()) {
//小結(jié)
//1. 如果正則表達式有() 即分組
//2. 取出匹配的字符串規(guī)則如下
//3. group(0) 表示匹配到的子字符串
//4. group(1) 表示匹配到的子字符串的第一組字串
//5. group(2) 表示匹配到的子字符串的第2組字串
//6. ... 但是分組的數(shù)不能越界.
System.out.println("找到: " + matcher.group(0));//找到: 1998
System.out.println("第1組()匹配到的值=" + matcher.group(1));//19
System.out.println("第2組()匹配到的值=" + matcher.group(2));//98
}
}
}
語法
\\符號說明:在我們使用正則表達式去檢索某些特殊字符的時候,需要用到轉(zhuǎn)義字符,否則檢測不到結(jié)果,甚至?xí)箦e。
注意:在Java的正則表達式中,兩個\\代表其他語言中的一個\;
元字符
限定符
用于指定其前面的字符和組合項連續(xù)出現(xiàn)多少次。
符號 | 含義 | 示例 | 說明 | 匹配輸入 |
* | 指定字符重復(fù)0次或n次(無要求)零到多 | (abc)* | 僅包含任意個abc的字符串,等效于\w* | abc、 abcabcabc |
+ | 指定字符重復(fù)1次或n次(至少 一次)1到多 | m+(abc)* | 以至少1個m開頭,后接任意個abc的字 符串 | m、mabc、 mabcabc |
? | 指定字符重復(fù)0次或1次(最多 一次)0到1 | m+abc? | 以至少1個m開頭,后接ab或abc的字符 串 | mab、mabc、mmmab. mmabc |
{} | 只能輸入n個字符 | [abcd]{3} | 由abcd中字母組成的任意長度為3的字 符串 | abc、dbc、adc |
{n,} | 指定至少n個匹配 | [abcd]{3,} | 由abcd中字母組成的任意長度不小于3的字符串 | aab、dbc、aaabdc |
{n,m} | 指定至少n個但不多于m個匹配 | [abcd]{3,5} | 由abcd中字母組成的任意長度不小于3,不大于5的字符串 | abc、abcd、aaaaa、bcdab |
java默認為
貪婪匹配
。
- 即:在限定出現(xiàn)次數(shù)里,優(yōu)先匹配出現(xiàn)
次數(shù)最多
的一組。- 例如:用a{3,5}來匹配aaaaaacx,返回的式aaaaa。
- 例如:
a.*b
,它將會匹配最長的以a開始,以b結(jié)束的字符串。如果用它來搜索aabab的
話,它會匹配整個字符串a(chǎn)abab。
?
組合的時候,它只作用于離他最近的那一個字符。
- 例如:
m+abc?
中,?
只作用于字符c。如果想要使用非貪婪匹配(懶惰匹配),則在限定符后面加上
?
即可。
a.*?b
匹配最短的,以a開始,以b結(jié)束的字符串。如果把它應(yīng)用于aabab的話,它會匹配aab(第一到第三個字符)和ab(第四到第五個字符)
選擇匹配符
在匹配某個字符串的時候是選擇性的,即可以匹配這個,也可以匹配那個。
符號
|
符號 | 示例 | 解釋 |
| | 匹配“|”之前或之后的表達式 | ab|cd | ab或者cd |
分組組合和反向引用符
1、分組
- ?我們可以用圓括號組成一個比較復(fù)雜的四配模式,那么一個圓括號的部分我們可以看作是一個子表達式或一個分組。
2、捕獲分組
- ?把正則表達式中子表達式或分組匹配的內(nèi)容,保存到內(nèi)存中以數(shù)字編號或顯式命名的組里,方便后面引用,從左向右,以分組的左括號為標志,第一個出現(xiàn)的分組的組號為1,第二個為2,以此類推。組0代表的是整個正則式。
常用分組構(gòu)造形式 | 說明 |
(pattern) | 非命名捕獲。捕獲匹配的子字符串。編號為零的第一個捕獲是由整個正則表達式模式匹配的文本,其它捕獲結(jié)果則根據(jù)左括號的順序從1開始自動編號。(在分析底層源碼的時候說過) |
(?pattern) | 命名捕獲。將匹配的子字符串捕獲到一個組名稱或編號名稱中。用于name的字符串不能包括任何標點符號,并且不能以數(shù)字開頭??梢允褂脝我柼娲饫ㄌ?,例如(?`name`) |
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Reg02 {
public static void main(String[] args) {
String test = "020-85652222";
//1.匹配目標
String reg="(0\\d{2})-(\\d{8})";
//2. 創(chuàng)建一個模式對象[即正則表達式對象]
Pattern pattern = Pattern.compile(reg);
//3.創(chuàng)建匹配器
Matcher mc= pattern.matcher(test);
if(mc.find()){
System.out.println("分組的個數(shù)有:"+mc.groupCount());
for(int i=0;i<=mc.groupCount();i++){
System.out.println("第"+i+"個分組為:"+mc.group(i));
}
}
}
}
輸出結(jié)果:
分組的個數(shù)有:2
第0個分組為:020-85652222
第1個分組為:020
第2個分組為:85652222
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("分組的個數(shù)有:"+mc.groupCount());
System.out.println(mc.group("quhao"));
System.out.println(mc.group("haoma"));
}
輸出結(jié)果:
分組的個數(shù)有:2
分組名稱為:quhao,匹配內(nèi)容為:020
分組名稱為:haoma,匹配內(nèi)容為:85653333
3、非捕獲分組
常用分組構(gòu)造形式 | 說明 |
(?:pattern) | 匹配pattern但不捕獲該匹配的子表達式,即它是一個非捕獲匹配,不存儲以后使用的匹配。這對于用“or”字符(|)組合模式部件的情況很有用。例如:`industr(?:y |
(?=pattern) | 它是一個非捕獲匹配。例如:`windows(?=95 |
(?!pattern) | 該表達式匹配不處于匹配pattern的字符串的起始點的搜索字符串。它是一個非捕獲匹配。例如:`windows(?!95 |
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("分組的個數(shù)有:"+mc.groupCount());
for(int i=0;i<=mc.groupCount();i++){
System.out.println("第"+i+"個分組為:"+mc.group(i));
}
}
輸出結(jié)果:
分組的個數(shù)有:1
第0個分組為:020-85653333
第1個分組為:85653333
//正向先行斷言
零寬度正預(yù)測先行斷言
語法:(?=pattern)
作用:匹配pattern表達式的前面內(nèi)容,不返回本身。
【正向先行斷言】可以匹配表達式前面的內(nèi)容,那意思就是(?=) 就可以匹配到前面的內(nèi)容了。
@Test
public void testAssert1(){
String regex = ".+(?=</span>)";
String context = "<span class=\"read-count\">閱讀數(shù):641</span>";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(context);
while (matcher.find()){
System.out.println(matcher.group());
}
}
//匹配結(jié)果:<span class="read-count">閱讀數(shù):641
//可是我們要的只是前面的數(shù)字呀,那也簡單咯,匹配數(shù)字 \d,那可以改成:
@Test
public void testAssert2(){
String regex = "\\d+(?=</span>)";
String context = "<span class=\"read-count\">閱讀數(shù):641</span>";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(context);
while (matcher.find()){
System.out.println(matcher.group());
}
}
//匹配結(jié)果:
//641
4、反向引用
?圓括號的內(nèi)容被捕獲
后,可以在這個括號后被使用,從而寫出一個比較實用的匹配模式,這個我們稱為反向引用
,這種引用既可以是在正則表達式內(nèi)部
,也可以是在正則表達式外部
,內(nèi)部反向引用\\
分組號,外部反向引用$
分組號。
public class RegTheory {
public static void main(String[] args) {
String content = "123-abc";
String regStr = "(?<i1>\\d)(?<i2>\\d)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()){
System.out.println(matcher.group("i1"));
System.out.println(matcher.group("i2"));
}
}
}
// 結(jié)果是1,2
正向后行斷言:
零寬度正回顧后發(fā)斷言,斷言在前,模式在后
語法:(?<=pattern)
作用:匹配pattern表達式的后面的內(nèi)容,不返回本身。
有先行就有后行,先行是匹配前面的內(nèi)容,那后行就是匹配后面的內(nèi)容啦。
@Test
public void testAssert3(){
String regex = "(?<=<span class=\"read-count\">閱讀數(shù):)\\d+";
String context = "<span class=\"read-count\">閱讀數(shù):641</span>";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(context);
while (matcher.find()){
System.out.println(matcher.group());
}
}
@Test
public void testRef(){
String context = "aabbxxccdddsksdhfhshh";
String regex = "(\\w)\\1";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(context);
while (matcher.find()){
System.out.println(matcher.group());
}
}
輸出結(jié)果:
aa
bb
xx
cc
dd
hh
//請編寫一個 Servlet, 可以獲取到瀏覽器所在電腦的操作系統(tǒng)版本和位數(shù)(32 還是 64), 顯示在頁面即可。
//(User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0)
public class ComputerServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String user_agent = req.getHeader("User-Agent");
//1.匹配目標
String regStr = "\\((.*)\\)";
//2. 創(chuàng)建一個模式對象[即正則表達式對象]
Pattern pattern = Pattern.compile(regStr);
//3. 創(chuàng)建一個匹配器對象
//說明:創(chuàng)建匹配器matcher, 按照 正則表達式的規(guī)則(pattern模式) 去匹配 content字符串
Matcher matcher = pattern.matcher(user_agent);
//4.開始循環(huán)匹配
while (matcher.find()) {
//匹配內(nèi)容,放在 matcher.group(0);
String group01 = matcher.group(1);
String[] split = group01.split(";");
System.out.println("操作系統(tǒng)=" +split[0]);//Windows NT 10.0
System.out.println("操作系統(tǒng)位數(shù)=" + split[1].trim());// Win64
}
}
}
特殊字符--轉(zhuǎn)義符
需要用到轉(zhuǎn)移符號的字符有以下:. * + ( ) $ / \ ? [ ] ^ { }
字符匹配符
符號 | 符號 | 示例 | 解釋 |
[] | 可接收的字符列表 | [efgh] | e、f、g、h中的任意1個字符 |
[^] | 不接收的字符列表 | [^abc] | 除a、b、c之外的任意1個字符, 包括數(shù)字和特殊符號 |
- | 連字符 | A-Z | 任意單個大寫字母 |
. | 匹配除\n以外的任何字節(jié) | a…b | 以a開頭,b結(jié)尾,中間包括2個任意字符的長度為4的字符串 |
\\d | 匹配單個數(shù)字字符,相當于[0-9] | \\d{3}(\\d)? | 包含3個或4個數(shù)字的字符串 |
\\D | 匹配單個非數(shù)字字符,相當于[^0-9] | \\D(\\d)* | 以單個非數(shù)字字符的開頭,后接任意個數(shù)字字符串 |
\\w | 匹配單個數(shù)字、大小寫字母字符,相當于[0-9a-zA-Z] | \\d{3}\\w{4} | 以3個數(shù)字字符開頭的長度為7的數(shù)字字母字符串 |
\\W | 匹配單個非數(shù)字,大小寫字母字符,相當于[^0-9a-zA-Z] | \\W+\\d{2} | 以至少1個非數(shù)字字母字符開頭,2個數(shù)字字符結(jié)尾的字符串 |
\\s | 匹配任何空白字符(空格,制表符等) | ||
\\S | 匹配任何非空白字符,和\\s剛好相反 |
定位符
符號 | 含義 | 示例 | 說明 | 匹配輸入 |
^ | 指定起始字符 | ^[0-9]+[a-z]* | 以至少1個數(shù)字開頭,后接任意個小寫字 母的字符串 | 123、6aa、555edf |
$ | 指定結(jié)束字符 | ^[0-9]\\-[a-z]+$ | 以1個數(shù)字開頭后接連字符“-”,并以至少1個小寫字母結(jié)尾的字符串 | 1-a |
\\b | 匹配目標字符串的邊界 | han\\b | 這里說的字符串的邊界指的是子串間有空格,或者是目標字符串的結(jié)束位置 | hanshunping sphan nnhan |
\\B | 匹配目標字符串的非邊界 | han\\B | 和b的含義剛剛相反 | hanshunping sphan nr |
其他
java正則表達式默認是區(qū)分字母的大小寫。如何實現(xiàn)不區(qū)分大小寫的方式?
- 方式一:在需要不區(qū)分大小寫的表達式前面寫上(?i)。但需要注意的是,如果是表達式中間的某個字符不區(qū)分大小寫的時候需要將它們括起來,例如:a((?i)b)c。
- 方式二:Pattern pat = Pattern.compile(regEx,Pattern.CASE_INSENSITIVE);
常用類
Pattern 類(模式類):
pattern 對象是一個正則表達式的編譯表示形式:指定為字符串的正則表達式必須首先被編譯為此類的實例。然后,可將得到的模式用于創(chuàng)建 Matcher 對象,依照正則表達式,該對象可以與任意字符序列匹配。執(zhí)行匹配所涉及的所有狀態(tài)都駐留在匹配器中,所以多個匹配器可以共享同一模式。
Pattern 類沒有公共構(gòu)造方法;首先調(diào)用其公共靜態(tài)編譯方法,可返回一個 Pattern 對象,?該方法接受一個正則表達式作為它的第一個參數(shù);,比如:Pattern r = Pattern.compile(pattem)
String content = "hello helloasdas";
String regStr = "hello";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()){
System.out.println(matcher.group(0));// 部分匹配,這里會匹配到兩個hello
}
boolean matches = Pattern.matches(regStr, content);
System.out.println(matches);
// 這是false,因為它是整體匹配,即正則表達式去匹配整個字符;表示字符串完全符合給出的正則表達式所表示的范圍。只要有一個字符不匹配則返回false串。
//matches()的底層也只是封裝了find()方法。
Matcher 類(匹配器類):
Matcher 對象是對輸入字符串進行解釋和匹配操作的引擎;與Pattern 類一樣,Matcher 也沒有公共構(gòu)造方法;需要調(diào)用 Pattern 對象的 matcher 方法來獲得一個 Matcher 對象
Macher類的常用方法
索引方法
序號 | 方法 | 說明 |
1 | public int start() | 返回以前匹配的初始索引。 |
2 | public int start(int group) | ?返回在以前的匹配操作期間,由給定組所捕獲的子序列的初始索引 |
3 | public int end() | 返回最后匹配字符之后的偏移量。 |
4 | public int end(int group) | 返回在以前的匹配操作期間,由給定組所捕獲子序列的最后字符之后的偏移量。 |
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("aaa2223bb");
m.find();//匹配2223
m.start();//返回3
m.end();//返回7,返回的是2223后的索引號
m.group();//返回2223
Mathcer m2=m.matcher("2223bb");
m.lookingAt(); //匹配2223
m.start(); //返回0,由于lookingAt()只能匹配前面的字符串,所以當使用lookingAt()匹配時,start()方法總是返回0
m.end(); //返回4
m.group(); //返回2223
Matcher m3=m.matcher("2223bb");
m.matches(); //匹配整個字符串
m.start(); //返回0,原因相信大家也清楚了
m.end(); //返回6,原因相信大家也清楚了,因為matches()需要匹配所有字符串
m.group(); //返回2223bb
Pattern p=Pattern.compile("([a-z]+)(\\d+)");
Matcher m=p.matcher("aaa2223bb");
m.find(); //匹配aaa2223
m.groupCount(); //返回2,因為有2組
m.start(1); //返回0 返回第一組匹配到的子字符串在字符串中的索引號
m.start(2); //返回3
m.end(1); //返回3 返回第一組匹配到的子字符串的最后一個字符在字符串中的索引位置.
m.end(2); //返回7
m.group(1); //返回aaa,返回第一組匹配到的子字符串
m.group(2); //返回2223,返回第二組匹配到的子字符串
查找方法
序號 | 方法 | 說明 |
1 | public boolean lookingAt() | ?嘗試將從區(qū)域開頭開始的輸入序列與該模式匹配。 |
2 | public boolean find() | 嘗試查找與該模式匹配的輸入序列的下一個子序列。 |
3 | public boolean find(int start) | 重置此匹配器,然后嘗試查找匹配該模式、從指定索引開始的輸入序列的下一個子序列。 |
4 | public boolean matches() | 嘗試將整個區(qū)域與模式匹配。 |
@Test
public void testMatches() {
String regex = "Mary";
String content1 = "Mary";
String content2 = "Mary is very handsome !";
String content3 = "My name is Mary.";
Pattern pattern = Pattern.compile(regex);
Matcher matcher1 = pattern.matcher(content1);
Matcher matcher2 = pattern.matcher(content2);
Matcher matcher3 = pattern.matcher(content3);
System.out.println("matches1(): " + matcher1.matches());
System.out.println("lookingAt1(): " + matcher1.lookingAt());
System.out.println("matches2(): " + matcher2.matches());
System.out.println("lookingAt2(): " + matcher2.lookingAt());
System.out.println("matches3(): " + matcher3.matches());
System.out.println("lookingAt3(): " + matcher3.lookingAt());
}
結(jié)果:
matches(): true
lookingAt(): true
matches(): false
lookingAt(): true
matches(): false
lookingAt(): false
//現(xiàn)在我們使用一下稍微高級點的正則匹配操作,例如有一段文本,里面有很多數(shù)字,而且這些數(shù)字是分開的,我們現(xiàn)在要將文本中所有數(shù)字都取出來,利用java的正則操作是那么的簡單.
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("我的QQ是:456456 我的電話是:0532214 我的郵箱是:aaa123@aaa.com");
while(m.find()) {
System.out.println(m.group());
}
輸出:
456456
0532214
123
package com.lhy.regex;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class regex02 {
public static void main(String[] args) {
Pattern p=Pattern.compile("\\d+");
Matcher m=p.matcher("我的QQ是:456456 我的電話是:0532214 我的郵箱是:aaa123@aaa.com");
while(m.find()) {
System.out.println(m.group());
System.out.print("start:"+m.start());
System.out.println(" end:"+m.end());
}
}
}
則輸出:
456456
start:6 end:12
0532214
start:19 end:26
123
start:36 end:39
每次執(zhí)行匹配操作后start(),end(),group()三個方法的值都會改變,改變成匹配到的子字符串的信息,以及它們的重載方法,也會改變成相應(yīng)的信息.?
注意:只有當匹配操作成功,才可以使用start(),end(),group()三個方法,否則會拋出java.lang.IllegalStateException,也就是當matches(),lookingAt(),find()其中任意一個方法返回true時,才可以使用.?
替換方法
序號 | 方法 | 說明 |
1 | public Matcher appendReplacement(StringBuffer sb, String replacement) | 實現(xiàn)非終端添加和替換步驟。 |
2 | public StringBuffer appendTail(StringBuffer sb) | 實現(xiàn)終端添加和替換步驟。 |
3 | public String replaceAll(String replacement) | ?替換模式與給定替換字符串相匹配的輸入序列的每個子序列。 |
4 | public String replaceFirst(String replacement) | ?替換模式與給定替換字符串匹配的輸入序列的第一個子序列。 |
5 | public static String quoteReplacement(String s) | 返回指定字符串的字面替換字符串。這個方法返回一個字符串,就像傳遞給Matcher類的appendReplacement 方法一個字面字符串一樣工作。 |
@Test
public void testReplace(){
String regex = "Mary";
String context = "My name is Mary, Mary is very handsome. ";
String replacement = "Lucy";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(context);
String result1 = m.replaceAll(replacement);
System.out.println(result1);
String result2 = m.replaceFirst(replacement);
System.out.println(result2);
}
結(jié)果:
My name is Lucy, itlils is very handsome.
My name is Lucy, itnanls is very handsome.
@Test
public void testAppend() {
String REGEX = "a*b";
String INPUT = "aabfooaabfooabfooabkkk";
String REPLACE = "-";
Pattern p = Pattern.compile(REGEX);
// 獲取 matcher 對象
Matcher m = p.matcher(INPUT);
StringBuffer sb = new StringBuffer();
m.find();
m.appendReplacement(sb, REPLACE);
System.out.println(sb);
m.find();
m.appendReplacement(sb, REPLACE);
System.out.println(sb);
m.appendTail(sb);
System.out.println(sb);
}
結(jié)果:
-
-foo-
-foo-fooabfooabkkk
PatternSyntaxException:
? ? ? ? ? ? 它表示一個正則表達式模式中的語法錯誤;PatternSyntaxException 是一個非強制異常類;
其他
String類中使用正則表達式的方法
方法 | 返回類型 | 功能 | 示例 |
matches() | boolean | 告知此字符串是否匹配給定的正則表達式。 | "-1234".matches("^-?\\d+$") => true |
replaceAll(String regex, String replacement) | String | 使用給定的 replacement 替換此字符串所有匹配給定的正則表達式的子字符串。 | "a1b2c3".replaceAll("[a-zA-z]", "") => 123 |
replaceFirst(String regex, String replacement) | String | 使用給定的 replacement 替換此字符串匹配給定的正則表達式的第一個子字符串。 | "Hello World! Hello Everyone!".replaceFirst("\\s", "") => HelloWorld! Hello Everyone! |
split(String regex) | String[] | 根據(jù)給定正則表達式的匹配拆分此字符串。 | "boo:and:foo".split(":") => { "boo", "and", "foo" } |
split(String regex, int limit) | String[] | 根據(jù)給定正則表達式的匹配拆分此字符串。 | "boo:and:foo".split(":", 5) => { "boo", "and", "foo" } |
split(String regex, int limit)
方法中l(wèi)imit 參數(shù)控制模式應(yīng)用的次數(shù),因此影響所得數(shù)組的長度。
- 如果該限制 n 大于 0,則模式將被最多應(yīng)用 n - 1 次,數(shù)組的長度將不會大于 n,而且數(shù)組的最后一項將包含所有超出最后匹配的定界符的輸入。
- 如果 n 為非正,那么模式將被應(yīng)用盡可能多的次數(shù),而且數(shù)組可以是任何長度。
- 如果 n 為 0,那么模式將被應(yīng)用盡可能多的次數(shù),數(shù)組可以是任何長度,并且結(jié)尾空字符串將被丟棄。
- 例如,字符串?
"boo:and:foo"
?使用這些參數(shù)可生成以下結(jié)果:
Regex | Limit | 結(jié)果 |
: | 2 | { "boo", "and:foo" } |
: | 5 | { "boo", "and", "foo" } |
: | -2 | { "boo", "and", "foo" } |
o | 5 | { "b", "", ":and:f", "", "" } |
o | -2 | { "b", "", ":and:f", "", "" } |
o | 0 | { "b", "", ":and:f" } |
調(diào)用此方法的?str.split(regex, n)
?形式與以下表達式產(chǎn)生的結(jié)果完全相同:Pattern.compile(regex).split(str, n)
?
String content = "hello helloasdas";
String str = content.replaceAll("(\\w)\\1+", "$1");
System.out.println(str); // 結(jié)果helo heloasdas
String content = "hehllos";
String regex = "^(h)\\w*s$";
boolean matches = content.matches("^(h)\\w*s$");
System.out.println(matches); //結(jié)果 true
String content = "hehllos";
String[] hs = content.split("h");
for (String h : hs) {
System.out.println(h);
} // 結(jié)果: e llos
常用正則表達式
校驗數(shù)字的表達式
1 數(shù)字:^[0-9]*$
2 n位的數(shù)字:^\d{n}$
3 至少n位的數(shù)字:^\d{n,}$
4 m-n位的數(shù)字:^\d{m,n}$
5 零和非零開頭的數(shù)字:^(0|[1-9][0-9]*)$
6 非零開頭的最多帶兩位小數(shù)的數(shù)字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
7 帶1-2位小數(shù)的正數(shù)或負數(shù):^(\-)?\d+(\.\d{1,2})?$
8 正數(shù)、負數(shù)、和小數(shù):^(\-|\+)?\d+(\.\d+)?$
9 有兩位小數(shù)的正實數(shù):^[0-9]+(.[0-9]{2})?$
10 有1~3位小數(shù)的正實數(shù):^[0-9]+(.[0-9]{1,3})?$
11 非零的正整數(shù):^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
12 非零的負整數(shù):^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$
13 非負整數(shù):^\d+$ 或 ^[1-9]\d*|0$
14 非正整數(shù):^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
15 非負浮點數(shù):^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
16 非正浮點數(shù):^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
17 正浮點數(shù):^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
18 負浮點數(shù):^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
19 浮點數(shù):^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$
校驗字符的表達式
1 漢字:^[\u4e00-\u9fa5]{0,}$
2 英文和數(shù)字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
3 長度為3-20的所有字符:^.{3,20}$
4 由26個英文字母組成的字符串:^[A-Za-z]+$
5 由26個大寫英文字母組成的字符串:^[A-Z]+$
6 由26個小寫英文字母組成的字符串:^[a-z]+$
7 由數(shù)字和26個英文字母組成的字符串:^[A-Za-z0-9]+$
8 由數(shù)字、26個英文字母或者下劃線組成的字符串:^\w+$ 或 ^\w{3,20}$
9 中文、英文、數(shù)字包括下劃線:^[\u4E00-\u9FA5A-Za-z0-9_]+$
10 中文、英文、數(shù)字但不包括下劃線等符號:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
11 可以輸入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+
12 禁止輸入含有~的字符:[^~\x22]+
特殊需求表達式
1 Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
2 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
3 InternetURL:[a-zA-z]+://[^\s]* 或 ^https://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
4 手機號碼:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
5 電話號碼("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$
6 國內(nèi)電話號碼(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
7 身份證號:
15或18位身份證:^\d{15}|\d{18}$
15位身份證:^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$
18位身份證:^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{4}$
8 短身份證號碼(數(shù)字、字母x結(jié)尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
9 帳號是否合法(字母開頭,允許5-16字節(jié),允許字母數(shù)字下劃線):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
10 密碼(以字母開頭,長度在6~18之間,只能包含字母、數(shù)字和下劃線):^[a-zA-Z]\w{5,17}$
11 強密碼(必須包含大小寫字母和數(shù)字的組合,不能使用特殊字符,長度在8-10之間):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
12 日期格式:^\d{4}-\d{1,2}-\d{1,2}
13 一年的12個月(01~09和1~12):^(0?[1-9]|1[0-2])$
14 一個月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
15 錢的輸入格式:
16 1.有四種錢的表示形式我們可以接受:"10000.00" 和 "10,000.00", 和沒有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$
17 2.這表示任意一個不以0開頭的數(shù)字,但是,這也意味著一個字符"0"不通過,所以我們采用下面的形式:^(0|[1-9][0-9]*)$
18 3.一個0或者一個不以0開頭的數(shù)字.我們還可以允許開頭有一個負號:^(0|-?[1-9][0-9]*)$
19 4.這表示一個0或者一個可能為負的開頭不為0的數(shù)字.讓用戶以0開頭好了.
把負號的也去掉,因為錢總不能是負的吧.下面我們要加的是說明可能的小數(shù)部分:^[0-9]+(.[0-9]+)?$
20 5.必須說明的是,小數(shù)點后面至少應(yīng)該有1位數(shù),所以"10."是不通過的,但是 "10" 和 "10.2" 是通過的:^[0-9]+(.[0-9]{2})?$
21 6.這樣我們規(guī)定小數(shù)點后面必須有兩位,如果你認為太苛刻了,可以這樣:^[0-9]+(.[0-9]{1,2})?$
22 7.這樣就允許用戶只寫一位小數(shù).下面我們該考慮數(shù)字中的逗號了,我們可以這樣:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
23 8.1到3個數(shù)字,后面跟著任意個 逗號+3個數(shù)字,逗號成為可選,而不是必須:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
24 備注:這就是最終結(jié)果了,別忘了"+"可以用"*"替代如果你覺得空字符串也可以接受的話(奇怪,為什么?)
最后,別忘了在用函數(shù)時去掉去掉那個反斜杠,一般的錯誤都在這里
25 xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
26 中文字符的正則表達式:[\u4e00-\u9fa5]
27 雙字節(jié)字符:[^\x00-\xff] (包括漢字在內(nèi),可以用來計算字符串的長度(一個雙字節(jié)字符長度計2,ASCII字符計1))
28 空白行的正則表達式:\n\s*\r (可以用來刪除空白行)
29 HTML標記的正則表達式:<(\S*?)[^>]*>.*?|<.*? /> (網(wǎng)上流傳的版本太糟糕,
上面這個也僅僅能部分,對于復(fù)雜的嵌套標記依舊無能為力)
30 首尾空白字符的正則表達式:^\s*|\s*$或(^\s*)|(\s*$) (可以用來刪除行首行尾的
空白字符(包括空格、制表符、換頁符等等),非常有用的表達式)
31 騰訊QQ號:[1-9][0-9]{4,} (騰訊QQ號從10000開始)
32 中國郵政編碼:[1-9]\d{5}(?!\d) (中國郵政編碼為6位數(shù)字)文章來源:http://www.zghlxwxcb.cn/news/detail-824337.html
33 IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址時有用)文章來源地址http://www.zghlxwxcb.cn/news/detail-824337.html
應(yīng)用案例
//將一個文件中的電話的中間四個數(shù)字替換成xxxx? 例子 15236985456 --> 152xxxx5456
姓名 年齡 郵箱 電話
張小強 23 526845845@163.com 13759685424
丁新新 20 238011792@qq.com 18011023709
李銀龍 20 liyinl1199w@163.com 17308811441
趙資本 19 anhuo69579@126.com 18234417225
李成剛 21 19713318@qq.com 13279906620
王鐵柱 20 ykl3987671@163.com 18802836971
張龍虎 22 zh199715@gmail.com 13888906654
李潔一 18 nl897665@yahoo.com 19762297581
劉大志 20 197685551@qq.com 15299744196
楊天天 19 86765ytian@126.com 17663999002
陳承成 21 rr796232@hotmail.com 18137541864
@Test
public void hidePhoneNumber() throws IOException {
StringBuilder sb = new StringBuilder();
// 1、將文件的內(nèi)容讀取到內(nèi)存
InputStream in = new FileInputStream("D:\\user.txt");
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0){
sb.append(new String(buf,0,len));
}
// 2、進行正則匹配
String regex = "(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])(\\d{4})(\\d{4})";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(sb.toString());
String result = matcher.replaceAll("$1xxxx$3");
System.out.println(result);
}
//通過scanner輸入一個字符串,判斷是否是一個郵箱?
public class TestEmail {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String email = scanner.next();
String regex = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(email);
boolean matches = matcher.matches();
if(matches){
System.out.println("您輸入的是一個郵箱!");
} else {
System.out.println("您輸入的不是郵箱!");
}
}
}
到了這里,關(guān)于Java學(xué)習(xí)(二十二)--正則表達式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!