1. 程式人生 > >Java正則表示式之分組和替換

Java正則表示式之分組和替換

正則表示式的子表示式(分組)不是很好懂,但卻是很強大的文字處理工具。

1 正則表示式熱身

匹配電話號碼
// 電話號碼匹配
// 手機號段只有 13xxx 15xxx 18xxxx 17xxx
System.out.println("18304072984".matches("1[3578]\\d{9}"));   // true

// 座機號:010-65784236,0316-3312617,022-12465647,03123312336
String regex = "0\\d{2}-?\\d{8}|0\\d{3}-?\\d{7}";
String telStr = "010-43367458";
System.out
.println(telStr.matches(regex)); // true
匹配郵箱
String mail = "[email protected]";
String reg = "[a-zA-Z_0-9][email protected][a-zA-Z0-9]+(\\.[a-zA-Z]+){1,2}";
System.out.println(mail.matches(reg));  // true
特殊字元替換

將不是中文的字元替換為空:

String input = "神探狄仁&*%$傑之四大天王@bdfbdbdfdgds23532";
String
reg = "[^\\u4e00-\\u9fa5]"; input = input.replaceAll(reg, ""); System.out.println(input); // 神探狄仁傑之四大天王

漢字的Unicode編碼範圍是:\u4e00-\u9fa5

2 分組

什麼是分組,直接引用 Java Api 中 Pattern 中的描述:

Capturing groups are numbered by counting their opening parentheses from left to right. In the expression ((A)(B(C))), for example, there are four such groups:
1. ((A)(B(C)))
2. (A)
3. (B(C))
4. (C)

可以根據有多少個左括號來來確定有多少個分組,括號裡的表示式都稱子表示式。

Eg1:
String regex = "\\$\\{([^{}]+?)\\}";
Pattern pattern = Pattern.compile(regex);
String input = "${name}-babalala-${age}-${address}";

Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
    System.out.println(matcher.group(0) + ", pos: " + matcher.start());
    System.out.println(matcher.group(1) + ", pos: " + matcher.start(1));
}

輸出:

${name}, pos: 0
name, pos: 2
${age}, pos: 17
age, pos: 19
${address}, pos: 24
address, pos: 26

group,翻譯成中文就是分組。
group()group(0)對應於整個正則表示式每次匹配到的內容,
group(1)表示括號中(一個子表示式分組)匹配到的內容。

Eg2:

為了更直觀的看分組,在Eg1的正則表示式上再多加一對括號:

String regex = "(\\$\\{([^{}]+?)\\})";
Pattern pattern = Pattern.compile(regex);
String input = "${name}-babalala-${age}-${address}";

Matcher matcher = pattern.matcher(input);
while (matcher.find()) {
    System.out.println(matcher.group(0) + ", pos: " + matcher.start());
    System.out.println(matcher.group(1) + ", pos: " + matcher.start(1));
    System.out.println(matcher.group(2) + ", pos: " + matcher.start(2));
}

輸出:

${name}, pos: 0
${name}, pos: 0
name, pos: 2
${age}, pos: 17
${age}, pos: 17
age, pos: 19
${address}, pos: 24
${address}, pos: 24
address, pos: 26

由此可得出一對括號一個分組,可以通過左括號數來確定有多少個分組。

通過group()獲取分組中的匹配字串應用場景很廣泛,
在筆者的一個專案中,通過使用這個特性實現了很有意思的萬用字元替換,感動!

3 分組替換

Eg1:
String tel = "18304072984";
// 括號表示組,被替換的部分$n表示第n組的內容
tel = tel.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
System.out.print(tel);   // output: 183****2984

replaceAll 是一個替換字串的方法,正則表示式中括號表示一個分組,replaceAll 的引數 2 中可以使用 $n(n 為數字)來依次引用子表示式中匹配到的分組字串,"(\\d{3})\\d{4}(\\d{4})", "$1****$2",分為前(前三個數字)中間四個數字(最後四個數字) 替換為(第一組數字保持不變 $1)(中間為 * )(第二組數字保持不變 $2)

Eg2:
String one = "hello girl hi hot".replaceFirst("(\\w+)\\s+(\\w+)", "$2 $1"); 
String two = "hello girl hi hot".replaceAll("(\\w+)\\s+(\\w+)", "$2 $1"); 
System.out.println(one);   // girl hello hi hot
System.out.println(two);   // girl hello hot hi

理解了Eg1,這個例子也自然就理解了。

Eg3:

來一個實用的例子,重複標點符號替換:

String input = "假如生活欺騙了你,,,相信吧,,,快樂的日子將會來臨!!!…………";

// 重複標點符號替換
String duplicateSymbolReg = "([。?!?!,]|\\.\\.\\.|……)+";
input = input.replaceAll(duplicateSymbolReg, "$1");
System.out.println(input);

輸出:

假如生活欺騙了你,相信吧,快樂的日子將會來臨!……

正則表示式:([。?!?!,]|\\.\\.\\.|……)+,括號中是一個分組:表示一個標點符號,+表示這個分組出現一次或多次,$1分組的內容(一個標點符號)。replaceAll 就使用$1去對字串進行替換了。

Eg4:

IP地址排序

String ip = "192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30";
ip = ip.replaceAll("(\\d+)", "00$1");
System.out.println(ip);

ip = ip.replaceAll("0*(\\d{3})", "$1");
System.out.println(ip);
String[] strs = ip.split(" ");

Arrays.sort(strs);
for (String str : strs) {
    str = str.replaceAll("0*(\\d+)", "$1");
    System.out.println(str);
}

輸出:

00192.0068.001.00254 00102.0049.0023.00013 0010.0010.0010.0010 002.002.002.002 008.00109.0090.0030
192.068.001.254 102.049.023.013 010.010.010.010 002.002.002.002 008.109.090.030
2.2.2.2
8.109.90.30
10.10.10.10
102.49.23.13
192.68.1.254
  1. 讓IP地址的每一段都是3位,替換之後有4位的情況
  2. 保證IP地址每一段都是3位
  3. 排序之

寫到這裡,筆者不禁感嘆,真的很強大!

4 反向引用

使用小括號指定一個子表示式分組後,匹配這個子表示式的文字可以在表示式或其它程式中作進一步的處理。預設情況下,每個分組會自動擁有一個組號,規則是:以分組的左括號為標誌,從左向右,第一個分組的組號為1,第二個為2,以此類推。

Eg:
/* 這個正則表示式表示 安安靜靜 這樣的疊詞 */
String regex = "(.)\\1(.)\\2";  
System.out.println("安安靜靜".matches(regex));   // true
System.out.println("安靜安靜".matches(regex));   // false

上面 (.) 表示一個分組,裡面 . 表示任意字元,每一個字元都是一個分組,
\\1表示組1()又出現了一次,\\2表示組2()又出現了一次。

那匹配 安靜安靜,怎麼寫正則表示式?根據上面的例子,將安靜分成一個組,然後這個組又出現了一次就是安靜安靜

String regex = "(..)\\1";  
System.out.println("安靜安靜".matches(regex));   // true
System.out.println("安安靜靜".matches(regex));   // false

5 反向引用替換

Eg1:
String str = "我我...我我...我要..要要...要要...找找找一個....女女女女...朋朋朋朋朋朋...友友友友友..友.友...友...友友!!!";

/*將 . 去掉*/
str = str.replaceAll("\\.+", "");
System.out.println(str);

str = str.replaceAll("(.)\\1+", "$1");
System.out.println(str);

輸出:

我我我我我要要要要要找找找一個女女女女朋朋朋朋朋朋友友友友友友友友友友!!!
我要找一個女朋友!

(.)表示任意一個字元都會成為一個分組;\\1+ 引用分組(一個字元),表示出現1次或多次這個分組。 $1引用分組(.)將多個重複字元替換成一個字元。

Eg2:

替換重複出現的兩位數之間的內容:

"xx12abdd12345".replaceAll("(\\d{2}).+?\\1", "");  //結果為 xx345

是不是覺得很神奇!

相關推薦

Java表示式分組替換

正則表示式的子表示式(分組)不是很好懂,但卻是很強大的文字處理工具。 1 正則表示式熱身 匹配電話號碼 // 電話號碼匹配 // 手機號段只有 13xxx 15xxx 18xxxx 17xxx System.out.println("18304

java表示式捕獲分組與Back引用

一.捕獲分組 java正則表示式中以()括起來的內容表示一個分組,像((A)(B(C)))這個表示式中,共存在四個分組: 1.ABC 2.A 3.BC 4.C 很容易發現,分組是按照左邊的括號出現的順序來標號的 這就是捕獲分組 二.Back引用 我們以下面這個正則表示式為例

JAVA表示式區分IPv4IPv6地址

PS*程式碼直接見第二部分: 一、進入正題前先說說JAVA正則表示式相關概念: 1、常用字元類: [abc] == a||b||c   [a-zA-Z] == 所有大小寫字母中的任意一個      [0-9A-Za-z] == 任意

Python學習筆記模式匹配與表示式使用不使用表示式

 隨筆記錄方便自己和同路人查閱。 #------------------------------------------------我是可恥的分割線-------------------------------------------   假設你希望在字串中查詢電話號碼。你知道模式:3個數字,一

Word中使用表示式進行查詢替換(高效進行文書處理)

術語 開始前,我們先定義一對術語: 萬用字元指的是您可以用來代表一個或多個字元的鍵盤字元。例如,星號 (*) 通常代表一個或多個字元,問號 (?) 通常代表單個字元。 對我們來說,正則表示式指的是您可以用來查詢和替換文字模式的文字字元和萬用字元組合。文字字元指的是必須存在於目標文

關於java表示式中的 ^$的使用

java正則表示式的邊界匹配符中,有兩個比較常用的字元:“ ^ ”和“ $ ”,這兩個字元理解起來比較容易混淆。先說下這兩個字元的含義: “ ^ ”:匹配輸入字串開始的位置。如果設定了 RegExp 物件的 Multiline 屬性,^ 還會與”\n”或”\r

java:表示式的概述簡單使用

public class Demo1_Regex { public static void main(String[] args) { // TODO Auto-generated method

表示式分組捕獲、條件表示式、平衡組

其實我是想說平衡組,但我並是想寫一篇給零基礎的朋友們閱讀,我希望你是對正則有所瞭解,對平衡組不太瞭解的朋友閱讀。如果已經瞭解,看看也無妨。多一點思路。 分組捕獲 - () 就是用括號把要匹配的內容擴起來 命名分組捕獲 - (?<name>)或(?'

理解 Java 表示式怪異的 \\ \\\\,讓您見怪不怪

原文連線:http://unmi.cc/understand-java-regex-backslash/#more-2880 Java 語言裡的幾大變革,一為 jdk1.4 引入的正則表示式,jdk1.5 引入的泛型。沒有泛型之前有不少人曾想方設法從編譯器入手讓 Java

js表示式分組反向引用

 javascript的正則反引用是通過RegExp.$1,RegExp.$2反向引用的。 例子: var reg = /(/w+)~(/w+)/; var textt="dddd~123"; if(reg.test(textt)){ console.log(Reg

表示式分組(捕獲)、後向引用

       分組          正則表示式中的分組又稱為子表示式,就是把一個正則表示式的全部或部分當做一個整體進行   處理,分成一個或多個組。其中分組是使用“()”表示的。進行分組之後“()”裡面的內容就會被當   成一個整體來處理。          先看看一個

Java表示式擷取字串

正則表示式很強大,熟悉正則表示式可以少些很多程式碼。常見的有,驗證使用者名稱/密碼是否合法,擷取字串等。這篇文章主要圍繞擷取字串做個簡單的介紹; 假設有個需求:在一長段亂七八糟的字串中擷取需要的資訊。 這裡有一個亂七八糟的字串:fjsdh(1234567

Java表示式替換移除空行多餘的空格

這幾天重拾Java寫程式碼,需要操作文字檔案中的內容。 最終,要把內容裡的空行和多餘的連續空格移除,使用String裡的replace或者replaceAll,試了很多次都沒有成功。 最後發現需要使用正則表示式Regex。先把解決方案共享如下。 1. 移除多餘的連續空格,只

java表示式詳解(匹配、切割替換

正則表示式:符合一定規則的表示式。作用:用於專門操作字串。特點:用於一些特定的符號來表示一些程式碼操作,這樣就簡化書寫。所以學習正則表示式,就是在學習一些特殊符號的使用。好處:可以簡化對字串的複雜操作。弊端:符號定義越多,正則越長,閱讀性越差。 具體操作功能: 1,匹配:

java表示式替換空格換行符

public static String getStringNoBlank(String str) { if(str!=null && !"".equals(str)) { Pattern p = Pa

Java表示式過濾、替換,將一段文字中的英語單詞分別提取出,並統計詞頻,按詞頻排序。

最近在學習自然語言處理,在建立基礎標籤庫時,遇到一個需要提取語料中的英文單詞的工作,做好了現在來和大家分享下。 實現效果:讀取檔案內容,把其中的英文單詞提取出,並統計詞頻。提取時,原本不是連在一起的單詞可以分開獨立提取,例如:我的PPT和WORD,可以提取出PPT,WORD兩個單詞。 基本思

java表示式去除html中所有的標籤特殊HTML字元

關於java正則表示式去除html中所有的標籤和特殊HTML字元,結合我所做的專案總結的經驗: 總共分為三種:第一種適用於適用短的文章,將文章用正則表示式的方式拼接到程式碼中,有些繁瑣,其實不太實用。第二種就是直接將文件引入,進行更改,但是有一個小缺點,就是文件中的格式可能是utf-8格式的

java表示式分組( )分組

以下內容均為個人理解,方便後續複習用部落格整理起來,如果有誤,還望指正。。。。(以下均為java在eclipse中的正則表示式) ( )分組           在java正則表示式中,( )是分組的意思,依舊是所謂的捕獲組。每一個( )代表

java表示式、PatternMatcher類小結

  最近在實際開發中遇到了2個坑,都和正則表示式有關。一個是public String[] split(String regex),入參居然是正則表示式!!!另一個坑與Pattern、Matcher類的操作有關。都是對java的正則表示式不夠熟悉導致。特地整理一

Java表示式 常用

1匹配驗證-驗證Email是否正確 Java | 複製 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static void main(String[] ar