正則表達式(Regular Expression,簡稱 Regex)是文本處理的 “瑞士軍刀”,它通過簡潔的語法規則,實現對字符串的匹配、提取、替換與驗證。在前文哈希機制的學習中,我們瞭解到 “映射” 是核心邏輯;而正則表達式的核心,則是 “模式定義”—— 用特定語法描述目標文本的結構,再通過解釋器執行匹配操作。本文將從基礎語法拓展到進階技巧,結合 10 + 實戰場景,帶你掌握正則的更多使用方法。

一、正則基礎回顧:核心語法快速梳理

在學習進階用法前,先回顧正則的基礎語法元素,這些是構建複雜模式的 “積木”:

語法元素

含義

示例

普通字符

匹配自身(如字母、數字、符號)

abc 匹配字符串中的 “abc”

元字符

具有特殊含義的字符(需轉義:\)

. 匹配任意字符(除換行)

量詞

定義前面元素的匹配次數

a{2,3} 匹配 “aa” 或 “aaa”

字符類

匹配一組字符中的任意一個

[a-z0-9] 匹配小寫字母或數字

分組

將多個元素視為一個整體

(ab)+ 匹配 “ab”“abab” 等

斷言

匹配位置(不消耗字符),分為正向 / 負向、先行 / 後行

a(?=b) 匹配後面跟 “b” 的 “a”

關鍵提醒:不同語言中,正則的轉義規則可能不同(如 Java 需雙重轉義:\\.,Python 只需單次轉義:\.),需結合具體語言調整。

二、進階用法 1:量詞的靈活運用 —— 從精確到模糊匹配

基礎量詞(* + ? {n,m})是正則的核心,但進階場景中需結合 “貪婪 / 非貪婪模式”“邊界匹配” 實現更精準的控制。

1. 貪婪與非貪婪模式:控制匹配長度

正則默認是 “貪婪模式”—— 儘可能匹配更長的字符串;在量詞後加?可切換為 “非貪婪模式”—— 儘可能匹配更短的字符串。

實戰場景:提取 HTML 標籤中的內容

<!-- 目標文本 --><div class="title">正則教程</div><div class="content">進階用法</div>
  • 貪婪模式:/<div.*>(.*)<\/div>/

匹配結果:從第一個<div到最後一個</div>,內容為 “正則教程進階用法”(匹配過長,包含多餘標籤);

  • 非貪婪模式:/<div.*?>(.*?)<\/div>/

匹配結果:分兩次匹配,第一次提取 “正則教程”,第二次提取 “進階用法”(精準匹配單個標籤內容)。

常用非貪婪量詞:

貪婪量詞

非貪婪量詞

含義

示例

*

*?

匹配 0 次或多次,儘可能少匹配

a*? 匹配 “aaab” 中的 “”“a”“a”“a”

+

+?

匹配 1 次或多次,儘可能少匹配

a+? 匹配 “aaab” 中的 “a”

{n,m}

{n,m}?

匹配 n~m 次,儘可能少匹配

a{2,3}? 匹配 “aaa” 中的 “aa”

2. 邊界匹配:限定匹配的位置

當需要匹配 “單詞開頭”“字符串首尾” 等特定位置時,需使用邊界匹配元字符:

邊界元字符

含義

示例

^

匹配字符串開頭(多行模式下匹配行首)

^abc 匹配 “abc123”,不匹配 “123abc”

$

匹配字符串結尾(多行模式下匹配行尾)

abc$ 匹配 “123abc”,不匹配 “abc123”

\b

匹配單詞邊界(單詞字符與非單詞字符的交界,如字母與空格、數字與符號)

\babc\b 匹配 “abc”“123 abc 456”,不匹配 “abcde”

\B

匹配非單詞邊界(與\b相反)

\Babc\B 匹配 “xabcx”,不匹配 “abc”

實戰場景:驗證手機號格式

需求:匹配 11 位手機號,且必須是純數字(不能包含其他字符)。

  • 錯誤表達式:1[3-9]\d{9}

問題:會匹配 “a13800138000b” 中的 “13800138000”(包含多餘字符);

  • 正確表達式:^1[3-9]\d{9}$

原理:^限定開頭,$限定結尾,確保整個字符串是 11 位手機號,不包含其他字符。

三、進階用法 2:分組與引用 —— 實現複雜結構匹配

分組(())不僅能將元素打包為整體,還能通過 “捕獲組” 提取匹配內容,通過 “反向引用” 複用之前的匹配結果,是處理重複結構、嵌套結構的核心技巧。

1. 捕獲組:提取匹配的子內容

用()包裹的部分稱為 “捕獲組”,每個捕獲組會被分配一個編號(從 1 開始),可通過編號提取對應內容。

實戰場景:提取 URL 中的域名與路徑

目標 URL:https://www.example.com/path?query=123

  • 正則表達式:^https?://([^/]+)(/.*)?$

分組解析:

  • 組 1:([^/]+) 匹配域名(www.example.com,[^/]表示非/的字符);
  • 組 2:(/.*)? 匹配路徑(/path?query=123,可選,?表示 0 次或 1 次)。
  • 提取結果(以 Python 為例):
import reurl = "https://www.example.com/path?query=123"pattern = r"^https?://([^/]+)(/.*)?$"result = re.match(pattern, url)print(result.group(1))  # 輸出:www.example.com(組1內容)print(result.group(2))  # 輸出:/path?query=123(組2內容)

命名捕獲組:更易讀的分組提取

當捕獲組較多時,用編號(1、2、3)容易混淆,可通過(?P<name>pattern)定義 “命名捕獲組”,再通過名稱提取內容。

實戰場景:提取日期中的年、月、日

目標日期:2025-11-15

  • 正則表達式:^(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})$
  • 提取結果(以 Python 為例):
date = "2025-11-15"pattern = r"^(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})$"result = re.match(pattern, date)print(result.group("year"))  # 輸出:2025print(result.group("month")) # 輸出:11

2. 反向引用:複用之前的匹配結果

反向引用用於匹配 “與之前捕獲組內容相同” 的字符串,語法為\n(n 為捕獲組編號)或(?P=name)(命名捕獲組)。

實戰場景 1:匹配重複的單詞(如 “the the”“and and”)

  • 正則表達式:\b(\w+)\b\s+\1\b

原理:

  • \b(\w+)\b 匹配一個單詞(組 1);
  • \s+ 匹配多個空格;
  • \1 反向引用組 1,匹配與之前相同的單詞;
  • 匹配結果:可識別 “this this”“hello hello” 等重複單詞,用於文本糾錯。

實戰場景 2:匹配 HTML 標籤(要求 opening 標籤與 closing 標籤一致)

目標文本:<h1>標題</h1>(正確標籤)、<div>內容</span>(錯誤標籤)

  • 正則表達式:<([a-z0-9]+)[^>]*>.*?</\1>

原理:

  • <([a-z0-9]+)[^>]*> 匹配 opening 標籤(如<h1>),組 1 捕獲標籤名(h1);
  • .*? 非貪婪匹配標籤內容;
  • </\1> 反向引用組 1,匹配對應的 closing 標籤(如</h1>);
  • 匹配結果:僅匹配<h1>標題</h1>,不匹配<div>內容</span>(標籤名不一致)。

3. 非捕獲組:僅分組,不捕獲

當只需將元素打包為整體,無需提取子內容時,用(?:pattern)定義 “非捕獲組”,避免佔用捕獲組編號(提升效率)。

實戰場景:匹配 “http” 或 “https” 開頭的 URL

  • 正則表達式:^(?:https?)://[^/]+

原理:(?:https?) 是 non-capturing group,僅表示 “http” 或 “https”,不單獨捕獲;

  • 優勢:若後續需添加其他捕獲組,編號從 1 開始,避免因無用分組導致編號混亂。

四、進階用法 3:斷言(零寬匹配)—— 匹配位置,不消耗字符

斷言(Assertion)是正則中最靈活的技巧之一,它不匹配具體字符,而是匹配 “字符之間的位置”(如 “a 後面是 b”“b 前面不是 a”),因此也稱為 “零寬匹配”。常見斷言分為四類:

斷言類型

語法

含義

示例

正向先行斷言

(?=pattern)

匹配 “後面跟 pattern” 的位置,不消耗字符

a(?=b) 匹配 “ab” 中的 “a”,不匹配 “ac” 中的 “a”

負向先行斷言

(?!pattern)

匹配 “後面不跟 pattern” 的位置,不消耗字符

a(?!b) 匹配 “ac” 中的 “a”,不匹配 “ab” 中的 “a”

正向後行斷言

(?<=pattern)

匹配 “前面是 pattern” 的位置,不消耗字符

(?<=a)b 匹配 “ab” 中的 “b”,不匹配 “cb” 中的 “b”

負向後行斷言

(?<!pattern)

匹配 “前面不是 pattern” 的位置,不消耗字符

(?<!a)b 匹配 “cb” 中的 “b”,不匹配 “ab” 中的 “b”

注意:部分語言(如 JavaScript)早期不支持後行斷言((?<=) (?<!)),需確認語言版本兼容性。

實戰場景 1:給數字添加千位分隔符(如 1234567→1,234,567)

需求:從右往左,每 3 位數字加一個逗號,不處理小數部分。

  • 正則表達式:(\d)(?=(\d{3})+(?!\d))

原理拆解:

  1. (\d) 匹配一個數字(後續要在它後面加逗號);
  2. (?=(\d{3})+(?!\d)) 正向先行斷言:
  • (\d{3})+ 匹配 1 組或多組 3 位數字;
  • (?!\d) 負向先行斷言:確保 3 位數字後沒有其他數字(即到字符串末尾或小數點);
  1. 整體含義:匹配 “後面跟着 3 的倍數個數字,且末尾無其他數字” 的單個數字,在它後面加逗號。
  • 替換邏輯(以 Python 為例):
num = "1234567890"pattern = r"(\d)(?=(\d{3})+(?!\d))"result = re.sub(pattern, r"\1,", num)  # 將匹配的數字替換為“數字+逗號”print(result)  # 輸出:1,234,567,890

實戰場景 2:提取密碼中的特殊字符(要求密碼包含至少 1 個特殊字符)

目標密碼:Pass@123(包含@)、123456(無特殊字符)

  • 正則表達式:(?<=[a-zA-Z0-9])([!@#$%^&*])(?=[a-zA-Z0-9])

原理:

  • (?<=[a-zA-Z0-9]) 正向後行斷言:特殊字符前面是字母或數字;
  • ([!@#$%^&*]) 捕獲特殊字符;
  • (?=[a-zA-Z0-9]) 正向先行斷言:特殊字符後面是字母或數字;
  • 匹配結果:僅提取Pass@123中的@,不匹配純數字密碼。

實戰場景 3:驗證密碼強度(至少 8 位,包含大小寫字母、數字、特殊字符)

  • 正則表達式:^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*]).{8,}$

原理(多個正向先行斷言組合):

  1. (?=.*[a-z]):至少包含 1 個小寫字母;
  2. (?=.*[A-Z]):至少包含 1 個大寫字母;
  3. (?=.*\d):至少包含 1 個數字;
  4. (?=.*[!@#$%^&*]):至少包含 1 個特殊字符;
  5. .{8,}:總長度至少 8 位;
  • 優勢:無需分組,直接通過斷言組合驗證多條件,簡潔高效。

五、進階用法 4:字符類與 Unicode—— 匹配多語言與特殊字符

基礎字符類(如[a-z] [0-9])僅適用於英文與數字,進階場景中需處理中文、 emoji、特殊符號等,需結合 Unicode 字符屬性與擴展字符類。

1. Unicode 字符屬性:匹配多語言文本

正則支持通過\p{Property}語法匹配具有特定 Unicode 屬性的字符,常見屬性:

Unicode 屬性

語法

含義

示例

字母

\p{L}

匹配任意語言的字母(包括中文、英文、日文等)

\p{L}+ 匹配 “正則 Expression”“abc”“あいう”

中文漢字

\p{Han}

僅匹配中文漢字(不包含標點、字母)

\p{Han}+ 匹配 “你好”“正則”,不匹配 “123”

數字

\p{N}

匹配任意語言的數字(包括阿拉伯數字、中文數字等)

\p{N}+ 匹配 “123”“一二三”“ⅰⅱⅲ”

空白字符

\p{Space}

匹配任意空白字符(空格、製表符、換行符等)

\p{Space} 匹配 “”“\t”“\n”

實戰場景:提取中文句子中的漢字(過濾標點與數字)

目標文本:正則表達式,真好用!2025年11月

  • 正則表達式:\p{Han}+
  • 匹配結果:提取 “正則表達式”“真好用”“年”“月”(過濾逗號、感嘆號、數字)。