1. 程式人生 > >恭喜你,Get到一份 正則表示式 食用指南

恭喜你,Get到一份 正則表示式 食用指南

先贊後看,養成習慣

前言

正則表示式

正則表示式: 定義一個搜尋模式的字串。

正則表示式可以用於搜尋、編輯和操作文字。

正則對文字的分析或修改過程為:首先正則表示式應用的是文字字串(text/string),它會以定義的模式從左到右匹配文字,每個源字元只匹配一次。

Java中正則表示式的使用

字串內建正則

在 Java 中有四個內建的執行正則表示式的方法,分別是 matches()split())replaceFirst()replaceAll()。注意 replace() 方法不支援正則表示式。

方法 描述
s.matches("regex") 當僅且當正則匹配整個字串時返回 true
s.split("regex") 按匹配的正則表示式切片字串
s.replaceFirst("regex", "replacement") 替換首次匹配的字串片段
s.replaceAll("regex", "replacement") 替換所有匹配的字元

示例程式碼

 System.out.println("lby".matches("lby"));
            System.out.println("----------");

            String[] array = "l b y".split("\\s");
            for (String item : array) {
                System.out.println(item);
            }
            System.out.println("----------");

            System.out.println("l b y".replaceFirst("\\s", "-"));
            System.out.println("----------");

            System.out.println("l b y".replaceAll("\\s", "-"));

執行結果

true
----------
l
b
y
----------
l-b y
----------
l-b-y

regex包

java.util.regex 包主要包括以下三個類:

  1. Pattern 類

    pattern 物件是一個正則表示式的編譯表示。Pattern 類沒有公共構造方法。要建立一個 Pattern 物件,你必須首先呼叫其公共靜態編譯方法,它返回一個 Pattern 物件。該方法接受一個正則表示式作為它的第一個引數。

  2. Matcher 類

    Matcher 物件是對輸入字串進行解釋和匹配操作的引擎。與Pattern 類一樣,Matcher 也沒有公共構造方法。你需要呼叫 Pattern 物件的 matcher 方法來獲得一個 Matcher 物件。

  3. PatternSyntaxException

    PatternSyntaxException 是一個非強制異常類,它表示一個正則表示式模式中的語法錯誤。

Java 中regex 包使用正則表示式基本步驟

  1. 通過正則表示式建立模式物件 Pattern。
  2. 通過模式物件 Pattern,根據指定字串建立匹配物件 Matcher。
  3. 通過匹配物件 Matcher,根據正則表示式操作字串。

例如


import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TestRegex {
    public static void main(String[] args) {
        //定義一個字串
        String text = "Hello Regex!";
        //建立一個Pattern物件  可以認為根據正則表示式獲取一個對應的物件
        Pattern pattern = Pattern.compile("\\w+");
        // Java 中忽略大小寫,有兩種寫法:
        // Pattern pattern = Pattern.compile("\\w+", Pattern.CASE_INSENSITIVE);
        // Pattern pattern = Pattern.compile("(?i)\\w+"); // 推薦寫法
        Matcher matcher = pattern.matcher(text);
        // 遍例所有匹配的序列
        while (matcher.find()) {
            System.out.print("Start index: " + matcher.start());
            System.out.print(" End index: " + matcher.end() + " ");
            System.out.println(matcher.group());
        }
        
    }
}

執行的結果為:

Start index: 0 End index: 5 Hello

Start index: 6 End index: 11 Regex、

以上程式碼看不懂沒有關係,提前感受一下正則的神奇,接下來我們學習一下正則表示式的的語法。

正則表示式的語法

常見匹配符號

正則表示式 描述
. 匹配所有單個字元,除了換行符(Linux 中換行是 \n,Windows 中換行是 \r\n
^regex 正則必須匹配字串開頭
regex$ 正則必須匹配字串結尾
[abc] 複選集定義,匹配字母 a 或 b 或 c
[abc][vz] 複選集定義,匹配字母 a 或 b 或 c,後面跟著 v 或 z
[^abc] 當插入符 ^ 在中括號中以第一個字元開始顯示,則表示否定模式。此模式匹配所有字元,除了 a 或 b 或 c
[a-d1-7] 範圍匹配,匹配字母 a 到 d 和數字從 1 到 7 之間,但不匹配 d1
XZ 匹配 X 後直接跟著 Z
X|Z 匹配 X 或 Z

元字元

元字元是一個預定義的字元。

正則表示式 描述
\d 匹配一個數字,是 [0-9] 的簡寫
\D 匹配一個非數字,是 [^0-9] 的簡寫
\s 匹配一個空格,是 [ \t\n\x0b\r\f] 的簡寫
\S 匹配一個非空格
\w 匹配一個單詞字元(大小寫字母、數字、下劃線),是 [a-zA-Z_0-9] 的簡寫
\W 匹配一個非單詞字元(除了大小寫字母、數字、下劃線之外的字元),等同於 [^\w]

限定符

限定符定義了一個元素可以發生的頻率。

正則表示式 描述 舉例
* 匹配 >=0 個,是 {0,} 的簡寫 X* 表示匹配零個或多個字母 X,.*表示匹配任何字串
+ 匹配 >=1 個,是 {1,} 的簡寫 X+ 表示匹配一個或多個字母 X
? 匹配 1 個或 0 個,是 {0,1} 的簡寫 X? 表示匹配 0 個或 1 個字母 X
{X} 只匹配 X 個字元 \d{3} 表示匹配 3 個數字,.{10}表示匹配任何長度是 10 的字串
{X,Y} 匹配 >=X 且 <=Y 個 \d{1,4} 表示匹配至少 1 個最多 4 個數字
*? 如果 ? 是限定符 *+?{} 後面的第一個字元,那麼表示非貪婪模式(儘可能少的匹配字元),而不是預設的貪婪模式

分組和反向引用

小括號 () 可以達到對正則表示式進行分組的效果。

模式分組後會在正則表示式中建立反向引用。反向引用會儲存匹配模式分組的字串片斷,這使得我們可以獲取並使用這個字串片斷。

在以正則表示式替換字串的語法中,是通過 $ 來引用分組的反向引用,$0 是匹配完整模式的字串(注意在 JavaScript 中是用 $& 表示);$1 是第一個分組的反向引用;$2 是第二個分組的反向引用,以此類推。

示例:

package com.baizhi.test;

public class RegexTest {

    public static void main(String[] args) {
        // 去除單詞與 , 和 . 之間的空格
        String Str = "Hello , World .";
        String pattern = "(\\w)(\\s+)([.,])";
        // $0 匹配 `(\w)(\s+)([.,])` 結果為 `o空格,` 和 `d空格.`
        // $1 匹配 `(\w)` 結果為 `o` 和 `d`
        // $2 匹配 `(\s+)` 結果為 `空格` 和 `空格`
        // $3 匹配 `([.,])` 結果為 `,` 和 `.`
        System.out.println(Str.replaceAll(pattern, "$1$3")); // Hello, World.
    }
}

上面的例子中,我們使用了 [.] 來匹配普通字元 . 而不需要使用 [\\.]。因為正則對於 [] 中的 .,會自動處理為 [\.],即普通字元 . 進行匹配。

否定先行斷言(Negative lookahead)

我們可以建立否定先行斷言模式的匹配,即某個字串後面不包含另一個字串的匹配模式。

否定先行斷言模式通過 (?!pattern) 定義。比如,我們匹配後面不是跟著 "b" 的 "a":

a(?!b)

指定正則表示式的模式

可以在正則的開頭指定模式修飾符。

  • (?i) 使正則忽略大小寫。
  • (?s) 表示單行模式("single line mode")使正則的 . 匹配所有字元,包括換行符。
  • (?m) 表示多行模式("multi-line mode"),使正則的 ^$ 匹配字串中每行的開始和結束。

Java 中的反斜槓

反斜槓 \ 在 Java 中表示轉義字元,這意味著 \ 在 Java 擁有預定義的含義。

這裡例舉兩個特別重要的用法:

  • 在匹配 .{[(?$^* 這些特殊字元時,需要在前面加上 \\,比如匹配 . 時,Java 中要寫為 \\.,但對於正則表示式來說就是 \.
  • 在匹配 \ 時,Java 中要寫為 \\\\,但對於正則表示式來說就是 \\

注意:Java 中的正則表示式字串有兩層含義,首先 Java 字串轉義出符合正則表示式語法的字串,然後再由轉義後的正則表示式進行模式匹配。

正則表示式常見應用示例

中文的匹配

[\u4e00-\u9fa5]+ 代表匹配中文字。

public static void test3(){
        String str = "這裡有個新手易範的錯誤,就是正angongsi";
        Pattern pattern = Pattern.compile("[\\u4e00-\\u9fa5]+");
        Matcher matcher = pattern.matcher(str);
        while (matcher.find()) {
            System.out.println(matcher.group());
        }
    }

數字範圍的匹配

比如,匹配 1990 到 2017。

注意:這裡有個新手易範的錯誤,就是正則 [1990-2017],實際這個正則只匹配 01279 中的任一個字元。

正則表示式匹配數字範圍時,首先要確定最大值與最小值,最後寫中間值。

正確的匹配方式:

public static void test4(){
        String str = "1990\n2010\n2017\nsdfgadfggadfgdfgdfgafdgasfdga\n1998";
        // 這裡應用了 (?m) 的多行匹配模式,只為方便我們測試輸出
        // "^1990$|^199[1-9]$|^20[0-1][0-6]$|^2017$" 為判斷 1990-2017 正確的正則表示式
        Pattern pattern = Pattern.compile("(?m)^1990$|^199[1-9]$|^20[0-1][0-6]$|^2017$");
        Matcher matcher = pattern.matcher(str);
        while (matcher.find()) {
            System.out.println(matcher.group());
        }
    }

img 標籤的匹配

比如,獲取圖片檔案內容,這裡我們考慮了一些不規範的 img 標籤寫法:

public static void test5(){
         String str = "<img  src='aaa.jpg' /><img src=bbb.png/><img src=\"ccc.png\"/>" +
                    "<img src='ddd.exe'/><img src='eee.jpn'/>";
            // 這裡我們考慮了一些不規範的 img 標籤寫法,比如:空格、引號
            Pattern pattern = Pattern.compile("<img\\s+src=(?:['\"])?(?<src>\\w+.(jpg|png))(?:['\"])?\\s*/>");
            Matcher matcher = pattern.matcher(str);
            while (matcher.find()) {
                System.out.println(matcher.group("src"));
            }
    }

郵箱匹配

郵箱匹配的正則的寫法有很多,這裡給出一種參考的寫法。

合法E-mail地址:

  1. 必須包含一個並且只有一個符號“@”
  2. 第一個字元不得是“@”或者“.”
  3. 不允許出現“@.”或者.@
  4. 結尾不得是字元“@”或者“.”
  5. 允許“@”前的字元中出現“+”
  6. 不允許“+”在最前面,或者“+@”

等等

示例程式碼

public static void test6(){
         String check = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";  
         Pattern regex = Pattern.compile(check);  
         Matcher matcher = regex.matcher("[email protected]");  
         boolean isMatched = matcher.matches();  
         System.out.println(isMatched); 
    }

手機號匹配

    public static void test7(){
        String check = "^((13[0-9])|(15[^4])|(18[0-9])|(17[0-9])|(147))\\d{8}$"; 
         Pattern regex = Pattern.compile(check); 
         Matcher matcher = regex.matcher("18638693953"); 
         boolean isMatched = matcher.matches(); 
         System.out.println(isMatched); 
    }

url匹配

public static void test8(){
        String url = "http://www.lubingyang.com/";
        String regex = "(https?://(w{3}\\.)?)?\\w+\\.\\w+(\\.[a-zA-Z]+)*(:\\d{1,5})?(/\\w*)*(\\??(.+=.*)?(&.+=.*)?)?";
        boolean isMatched = Pattern.matches(regex, url);
        System.out.println(isMatched);
    }

求點贊,求關注,求轉發

歡迎關注本人公眾號:鹿老師的Java筆記,將在長期更新Java技術圖文教程和視訊教程,Java學習經驗,Java面試經驗以及Java實戰開發經驗。