我對正則表達式的理解
正則表達式Regex(Regular Expression),是一種通過定義由特定字符組成的表達式來對字符串進行匹配、查找、替換和切割的字符串操作工具蓉坎。
正則表達式中特定的一些字符
表達式 | 匹配內容 |
---|---|
字符 | |
x | 字符 x |
\\ | 反斜線字符 |
\0n | 帶有八進制值 0 的字符 n (0 <= n <= 7) |
\0nn | 帶有八進制值 0 的字符 nn (0 <= n <= 7) |
\0mnn | 帶有八進制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7) |
\xhh | 帶有十六進制值 0x 的字符 hh |
\uhhhh | 帶有十六進制值 0x 的字符 hhhh |
\t | 制表符 ('\u0009') |
\n | 新行(換行)符 ('\u000A') |
\r | 回車符 ('\u000D') |
\f | 換頁符 ('\u000C') |
\a | 報警 (bell) 符 ('\u0007') |
\e | 轉義符 ('\u001B') |
\cx | 對應于 x 的控制符 |
字符類 | |
[abc] | a胡嘿、b 或 c(簡單類) |
[^abc] | 任何字符蛉艾,除了 a、b 或 c(否定) |
[a-zA-Z] | a 到 z 或 A 到 Z衷敌,兩頭的字母包括在內(范圍) |
[a-d[m-p]] | a 到 d 或 m 到 p:[a-dm-p](并集) |
[a-z&&[def]] | d勿侯、e 或 f(交集) |
[a-z&&[^bc]] | a 到 z,除了 b 和 c:[ad-z](減去) |
[a-z&&[^m-p]] | a 到 z缴罗,而非 m 到 p:[a-lq-z](減去) |
預定義字符類 | |
. | 任何字符(與行結束符可能匹配也可能不匹配) |
\d | 數字:[0-9] |
\D | 非數字: [^0-9] |
\s | 空白字符:[ \t\n\x0B\f\r] |
\S | 非空白字符:[^\s] |
\w | 單詞字符:[a-zA-Z_0-9] |
\W | 非單詞字符:[^\w] |
邊界匹配器 | |
^ | 行的開頭 |
$ | 行的結尾 |
\b | 單詞邊界 |
\B | 非單詞邊界 |
\A | 輸入的開頭 |
\G | 上一個匹配的結尾 |
\Z | 輸入的結尾助琐,僅用于最后的結束符(如果有的話) |
\z | 輸入的結尾 |
Greedy數量詞 | |
X? | X,一次或一次也沒有 |
X* | X面氓,零次或多次 |
X+ | X兵钮,一次或多次 |
X{n} | X,恰好 n 次 |
X{n,} | X舌界,至少 n 次 |
X{n,m} | X掘譬,至少 n 次,但是不超過 m 次 |
正則表達式在Java中的表現形式
public final class Pattern
extends Object
implements Serializable
Pattern正則表達式的編譯表示形式呻拌。
指定為字符串的正則表達式必須首先被編譯為此類的實例葱轩。然后,可將得到的模式用于創(chuàng)建 Matcher 對象藐握,依照正則表達式靴拱,該對象可以與任意字符序列匹配。執(zhí)行匹配所涉及的所有狀態(tài)都駐留在匹配器中猾普,所以多個匹配器可以共享同一模式袜炕。
因此,典型的調用順序是
Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();
在僅使用一次正則表達式時抬闷,可以方便地通過此類定義 matches 方法妇蛀。此方法編譯表達式并在單個調用中將輸入序列與其匹配。語句
boolean b = Pattern.matches("a*b", "aaaaab");
等效于上面的三個語句笤成,盡管對于重復的匹配而言它效率不高评架,因為它不允許重用已編譯的模式。
使用正則表達式對字符串進行匹配
使用正則表達式對字符串進行匹配有三種方式:
1)使用字符串的對象的matches()方法
2)使用Matcher的對象的matches()方法
3)使用Pattern類的matches()方法
匹配的特點:
1)根據正則表達式的規(guī)則對整個字符串進行匹配
2)匹配結果返回對應的布爾值
使用方法:
請參考下面匹配字符串是否為電話號碼的實例
public class MatchTest {
public static void main(String[] args) {
System.out.println("一炕泳,使用字符串的對象的matches()方法");
matchDemo_1("13805646681");
matchDemo_1("03805646681");
matchDemo_1("13805Jia681");
matchDemo_1("138056");
System.out.println("二纵诞,使用Matcher的對象的matches()方法");
matchDemo_2("13805646681");
matchDemo_2("03805646681");
matchDemo_2("13805Jia681");
matchDemo_2("138056");
System.out.println("三,使用Pattern類的matches()方法");
matchDemo_3("13805646681");
matchDemo_3("03805646681");
matchDemo_3("13805Jia681");
matchDemo_3("138056");
}
/**
* 匹配字符串是否為電話號碼
* 匹配規(guī)則:
* 1.電話號碼以數字1開頭
* 2.電話號碼長度為11
* 3.電話號碼為全數字
* 對應的正則表達式:
* 1)"1\\d{10}"
* 解讀:
* 正則表達是第一個數是1培遵,所以它只能匹配以1開頭的字符串浙芙;
* \\d,因為Java中反斜杠會把它后面的字符進行轉移籽腕,所以\\d就是正則表達式中預定義字符類中的\d(== [0-9]),即能夠匹配數字0-9中的任意一個嗡呼;
* {10},代表前面的\d恰好出現10次皇耗,這樣加上第一個數1共有11個數字南窗,所以它只能匹配長度為11且全部為數字的字符串。
* 2)"1[0-9]{10}"
* 解讀:
* \d == [0-9]
*/
public static void matchDemo_1(String str) {
String regex = "1\\d{10}";
boolean isMatched = str.matches(regex);
System.out.println(str + (isMatched ? "是電話號碼" : "不是電話號碼"));
}
public static void matchDemo_2(String str) {
String regex = "1[0-9]{10}";
// 1郎楼,將正則表達式編譯成Pattern對象
Pattern p = Pattern.compile(regex);
// 2, 與字符串進行關聯(lián)万伤,生成Matcher對象
Matcher m = p.matcher(str);
// 3,對字符串進行操作
boolean isMatched = m.matches();
System.out.println(str + (isMatched ? "是電話號碼" : "不是電話號碼"));
}
public static void matchDemo_3(String str) {
String regex = "1\\d{10}";
boolean isMatched = Pattern.matches(regex, str);
System.out.println(str + (isMatched ? "是電話號碼" : "不是電話號碼"));
}
}
使用正則表達式對字符串進行替換
正則表達式既可以替換字符串中所有匹配到的字符呜袁,也可以只替換第一次匹配到的字符敌买,對應的兩個方法是replaceALL和replaceFirst,同樣在String對象和Matcher對象中都包含這兩個方法。
替換的特點:
1)可以將正則表達式匹配到的字符(串)替換為你指定的字符(串)
2)替換結果生成新的字符串
使用方法:
請參考下面疊詞替換的實例
public class StackedWordsReplace {
public static void main(String[] args) {
stackedWordsReplaceDemo_1();
stackedWordsReplaceDemo_2();
}
public static void stackedWordsReplaceDemo_1() {
// 將下面的字符串轉換成"我要學習編程阶界。"
String str = "我我我我我要要學學學編編編編程程程程虹钮。";
// 正則表達式中通過()創(chuàng)建一個捕獲組
// 捕獲組默認從1開始進行編號,可以通過從左到右計算開括號(左括號)個數和順序進行排序
// 例如膘融,在表達式 ((A)(B(C))) 中芜抒,存在四個這樣的組:((A)(B(C)))、(A)托启、(B(C))宅倒、(C)
// 正則表達式中的\n和$n分別在匹配環(huán)節(jié)和替換環(huán)節(jié)中引用捕獲組捕獲的內容,n代表數字1屯耸、2拐迁、3...
// "(.)\1+"解讀:
// .可以匹配任意字符,\\1即\1引用(.)的捕獲內容,+前面的字符出現一次或多次疗绣。
// 比如,當.匹配的到我的時候\1就是我线召,所以這個表達式能夠匹配到無數個我連續(xù)組成但最低不少兩個我的字符串。
// $1為替換的類容多矮,因為$1引用(.)的捕獲內容缓淹,所以當.匹配到什么就替換為什么
str = str.replaceAll("(.)\\1+", "$1");
System.out.println(str);
}
public static void stackedWordsReplaceDemo_2() {
String str = "我我我我我要要學學學編編編編程程程程哈打。";
String regex = "(.)\\1+";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
str = matcher.replaceAll("$1");
System.out.println(str);
}
}
使用正則表達式對字符串進行切割
使用正則表達式對字符串進行切割有兩種方式:
1)使用String對象的split方法
2)使用Pattern對象的split方法
切割的特點:
1)可以將正則表達式匹配到的字符(串)作為分隔符來對字符串進行切割
2)切割結果為子串組成的字符串數組
使用方法:
請參考下面的切割實例
public class SplitTest {
public static void main(String[] args) {
splitDemo_1();
splitDemo_2();
}
public static void splitDemo_1() {
// 將下面的字符串以.為分隔符進行切割
// 由于在正則表達式中.為預定義字符,所以需要用\進行轉義讯壶,
// 在Java中\(zhòng)也是轉義字符料仗,所以仍需要進行轉義
String str = "我.愛.中.國";
String regex = "\\.";
String[] strings = str.split(regex);
for (String s : strings) {
System.out.println(s);
}
}
public static void splitDemo_2() {
String str = "我.愛.中.國";
String regex = "\\.";
Pattern pattern = Pattern.compile(regex);
String[] strings = pattern.split(str);
for (String s : strings) {
System.out.println(s);
}
}
}
綜合案例演示
下面將演示綜合使用和切割來對IP地址進行排序
public class IPSort {
public static void main(String[] args) {
ipSort();
}
/**
* 將IP地址進行排序
*/
public static void ipSort() {
String ip = "127.0.0.1 192.168.0.1 114.114.114.114 8.8.8.8 10.2.33.134 255.255.255.255";
// 1.將IP地址全部替換為xxx.xxx.xxx.xxx樣式
ip = ip.replaceAll("\\w{1,3}", "00$0"); // 將IP地址每一段都添加00
System.out.println(ip);
ip = ip.replaceAll("0*(\\w{3})", "$1"); // 去除每一段多余的0,是每一段只保留三位數字
System.out.println(ip);
// 2.對字符串進行排序
String[] arr = ip.split(" ");
System.out.println(Arrays.toString(arr));
Arrays.sort(arr);
for (String s : arr) {
// 去除添加的0
s = s.replaceAll("0*(\\w+)", "$1");
System.out.println(s);
}
}
}
使用正則表達式對字符串進行查找
對字符串進行查找伏蚊,主要用的是Matcher對象的以下方法:
1)find()嘗試查找與該模式匹配的輸入序列的下一個子序列
2)group()返回上一次匹配操作所匹配的輸入子序列
3)reset(CharSequence input)將該模式應用到新的輸入序列
查找的特點:
1)可以將正則表達式匹配到的字符(串)逐個找出來
2)查找結果為一個個匹配的子串
3)必須逐個查找立轧,直接調用group()方法無法得到結果
使用方法:
請參考下面的爬去網頁中的電子郵箱實例
public class FindEmail {
public static void main(String[] args) {
findEmail();
}
public static void findEmail() {
// 簡單郵箱匹配規(guī)則
String reg = "\\w+@\\w+(\\.\\w+)+";
// 1.將正則表達式編譯成Pattern對象
Pattern p = Pattern.compile(reg);
Matcher m = null;
try {
URL url = new URL("https://www.douban.com/group/topic/70867518/");
URLConnection connection = url.openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
// 2.將字符串和Pattern對象進行關聯(lián),生成Matcher對象
if (m == null) {
m = p.matcher(line);
} else {
m.reset(line);
}
// 3.通過Matcher對象對字符串進行操作
while (m.find()) {
System.out.println(m.group());
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}