算法精講--正則表達式(二):分組、引用與高級匹配技術

算法精講–正則表達式(二):分組、引用與高級匹配技術 🚀

正則表達式的真正力量在于組合使用各種語法元素,創造出強大而精確的匹配模式!

—— 作者:無限大

推薦閱讀時間:25 分鐘

適用人群:已掌握基礎正則語法,希望提升實戰能力的開發者

引言:從基礎到組合的飛躍 🚀

在《算法精講–正則表達式(一)》中,我們學習了正則表達式的基礎知識:字符匹配、量詞和位置匹配。這些是構建正則表達式的基石,但真正讓正則表達式發揮強大威力的是組合使用這些基礎元素。

想象一下,基礎語法就像字母表中的字母,而組合技巧則是將這些字母組成單詞、句子和段落的語法規則。只有掌握了組合技巧,你才能真正用正則表達式解決復雜的文本處理問題。

本章將帶你探索正則表達式的組合藝術–分組與引用,讓你從正則表達式的初學者蛻變為匹配大師!


分組與引用:結構化匹配的藝術 🔄

1.1 什么是分組?為什么需要分組?

分組(Grouping) 是正則表達式中用于將多個字符或子表達式組合為一個邏輯單元的機制,通過圓括號 () 實現。分組的主要作用包括:

  1. 邏輯組合:將多個元素視為一個整體進行操作(如應用量詞)
  2. 捕獲數據:提取匹配結果中的特定部分
  3. 模式分支:通過 | 實現多個可選模式
  4. 引用匹配:在表達式內部或替換操作中引用已匹配的內容

沒有分組,正則表達式將無法處理復雜的結構化文本匹配。想象一下,如果不能將 ab 組合為一個整體,我們將無法匹配重復出現的 ab 序列。


1.2 分組的類型

1.2.1 捕獲組:提取匹配的子串 🎯

捕獲組(Capturing Group) 是正則表達式中最強大的組合工具之一,它允許你將匹配的部分內容保存到臨時變量中,以便后續使用。使用圓括號 () 可以創建捕獲組。

基本語法與工作原理
(表達式)例:ab+c,只能匹配abc、abbc、ababcb等(ab)+c,可以匹配abc、ababc、abababc等
實用示例

示例 1:提取日期中的年、月、日

// 匹配格式為 yyyy-mm-dd 的日期
const dateRegex = /(d{4})-(d{2})-(d{2})/;
const date = "2023-12-25";
const result = date.match(dateRegex);console.log(result[0]); // 輸出: 2023-12-25 (整個匹配)
console.log(result[1]); // 輸出: 2023 (第一個捕獲組: 年)
console.log(result[2]); // 輸出: 12 (第二個捕獲組: 月)
console.log(result[3]); // 輸出: 25 (第三個捕獲組: 日)

示例 2:交換姓名順序

import re# 將 "姓, 名" 格式轉換為 "名 姓"
name = "Doe, John"
# 使用 1 和 2 引用第一個和第二個捕獲組
formatted_name = re.sub(r'(w+), (w+)', r'2 1', name)print(formatted_name)  # 輸出: John Doe

1.2.2 非捕獲組:提高性能的技巧 ?

當你只需要對表達式進行分組,而不需要捕獲匹配結果時,可以使用非捕獲組(Non-capturing Group)。非捕獲組不會創建編號的引用(即不參與組計數,僅用于分組匹配,不會存儲匹配結果)從而提高性能并避免不必要的內存占用。

基本語法
(?:表達式)
實用示例

區分捕獲組與非捕獲組

import java.util.regex.Matcher;
import java.util.regex.Pattern;public class GroupExample {public static void main(String[] args) {String text = "apple,banana,orange";// 使用捕獲組Pattern capturePattern = Pattern.compile("(apple),(banana)");Matcher captureMatcher = capturePattern.matcher(text);if (captureMatcher.find()) {System.out.println("捕獲組數量: " + captureMatcher.groupCount()); // 輸出: 2}// 使用非捕獲組Pattern nonCapturePattern = Pattern.compile("(?:apple),(?:banana)");Matcher nonCaptureMatcher = nonCapturePattern.matcher(text);if (nonCaptureMatcher.find()) {System.out.println("非捕獲組數量: " + nonCaptureMatcher.groupCount()); // 輸出: 0}}
}

1.2.3 命名捕獲組:提高可讀性的高級技巧 🏷?

隨著正則表達式變得復雜,僅靠數字引用捕獲組會降低代碼的可讀性。命名捕獲組(Named Capturing Group) 允許你為捕獲組分配名稱,使正則表達式更易于理解和維護。

基本語法
(?<名稱>表達式)

引用命名捕獲組的語法因語言而異:

  • 在 JavaScript 中:k<名稱>$<名稱>
  • 在 Python 中:(?P=名稱) 或通過 group('名稱') 方法
  • 在 Java 中:k<名稱>group('名稱') 方法
實用示例

使用命名捕獲組解析 URL

// 定義正則表達式,用于匹配和解析URL結構。正則表達式使用命名捕獲組(如?<protocol>)標識關鍵部分。
// ^ 表示字符串起始;(?<protocol>https?) 匹配協議(http或https,s為可選)[[2]];
// :// 是固定分隔符;(?<domain>[^/]+) 匹配域名(非斜杠字符序列,直到遇到斜杠或結束);
// (?<path>/.*)? 匹配路徑(以斜杠開頭的任意字符序列,?表示路徑可選)[[5]];$ 表示字符串結束。
const urlRegex = /^(?<protocol>https?)://(?<domain>[^/]+)(?<path>/.*)?$/;// 示例URL字符串,包含協議、域名和路徑(含查詢參數)
const url = "https://www.example.com/path/to/resource?query=1";// 使用match方法執行正則匹配,返回結果對象。result.groups屬性存儲命名捕獲組的值[[8]]。
const result = url.match(urlRegex);// 輸出協議部分:result.groups.protocol訪問命名組,匹配"https"(s被捕獲)[[2]]
console.log(result.groups.protocol); // 輸出: https// 輸出域名部分:result.groups.domain訪問命名組,匹配"www.example.com"(域名不含斜杠)[[5]]
console.log(result.groups.domain); // 輸出: www.example.com// 輸出路徑部分:result.groups.path訪問命名組,匹配"/path/to/resource?query=1"(包含查詢參數)[[9]]
console.log(result.groups.path); // 輸出: /path/to/resource?query=1

1.3 分組引用:復用匹配結果 🔄

分組引用允許你在正則表達式中或替換操作中復用前面捕獲組匹配的內容,極大增強了模式匹配的靈活性和強大性。主要包括以下幾種類型:

1.3.1 反向引用:匹配重復文本

反向引用(Backreference) 允許你引用前面捕獲組匹配的內容,這對于匹配重復出現的文本模式特別有用。

基本語法:

  • 數字反向引用:\n (n 是捕獲組編號)
  • 命名反向引用:\k<名稱>(?P=name),后面的內容是 py 專屬語法

示例 1:匹配重復的單詞

// 定義待檢測文本(包含重復單詞 "is is" 和 "test test")
const text = "This is is a test test.";// 正則表達式:\b(\w+)\s+\1\b
// - \b:單詞邊界,確保匹配完整單詞
// - (\w+):捕獲組1,匹配一個或多個字母/數字/下劃線(單詞內容)
// - \s+:匹配一個或多個空白字符(如空格)
// - \1:反向引用,指向捕獲組1匹配的內容(要求后續內容與組1完全相同)
// - g:全局匹配模式
const duplicateRegex = /\b(\w+)\s+\1\b/g;// 執行匹配:返回所有符合正則的子串數組
const result = text.match(duplicateRegex);
console.log(result); // 輸出: [ 'is is', 'test test' ]

示例 2:匹配 HTML 標簽對

import re# 定義 HTML 字符串(含成對的 div 和 p 標簽)
html = "<div>這是一個 div 標簽</div><p>這是一個 p 標簽</p>"# 正則表達式:<(?P<tag>\w+)>.*?</(?P=tag)>
# - (?P<tag>\w+):命名捕獲組 "tag",匹配標簽名(如 "div")
# - .*?:非貪婪匹配標簽間任意內容
# - (?P=tag):命名反向引用,要求結束標簽名與 "tag" 組相同
pattern = r'<(?P<tag>\w+)>.*?</(?P=tag)>'# 執行匹配:返回所有標簽名的列表(僅返回捕獲組內容)
matches = re.findall(pattern, html)
print(matches)  # 輸出: ['div', 'p']

1.3.2 替換引用:在替換中使用捕獲內容

在替換操作中,可以使用特殊語法引用捕獲組的內容,實現文本轉換和重組。

不同語言中的替換引用語法:

  • JavaScript: $n${n} (數字引用), $<name> (命名引用)
  • Python: n (數字引用), (?P=name) (命名引用)
  • Java: $n (數字引用), ${name} (命名引用)

示例:格式化日期

// 將 yyyy-mm-dd 格式轉換為 mm/dd/yyyy 格式
const date = "2023-12-25";
// 使用 $2 和 $3 引用月和日,$1 引用年
const formattedDate = date.replace(/(\d{4})-(\d{2})-(\d{2})/, "$2/$3/$1");console.log(formattedDate); // 輸出: 12/25/2023

1.4 分組的高級應用 🚀

條件表達式:基于捕獲組的條件匹配 🧩

條件表達式(Conditional Expression) 允許根據前面的捕獲組是否匹配來決定應用哪個模式。

基本語法:

(?(組號或名稱)匹配成功時的模式|匹配失敗時的模式)

示例:處理可選的引號

import retext = 'name=John name="Doe"'# 正則表達式分解:
# 1. name= : 匹配字面量
# 2. (?:...) : 非捕獲組,表示兩種匹配可能
# 3. "(?P<quoted>[^"]+)" : 帶引號的情況
#    - " : 匹配開頭的引號
#    - (?P<quoted>[^"]+) : 命名捕獲組,匹配除"外的任意字符(至少1個)
#    - " : 匹配結尾的引號
# 4. | : 或邏輯
# 5. (?P<unquoted>\w+) : 不帶引號的情況
#    - \w+ : 匹配字母/數字/下劃線(至少1個)
pattern = r'name=(?:"(?P<quoted>[^"]+)"|(?P<unquoted>\w+))'# 使用finditer獲取所有匹配的迭代器對象(保持匹配順序)
matches = re.finditer(pattern, text)for match in matches:# 優先檢查帶引號的分組(因為正則中帶引號的模式在前)if match.group('quoted'):# 當quoted分組有匹配內容時,輸出帶引號的值print(f'帶引號的值: {match.group("quoted")}')  # 注意使用雙引號避免沖突else:# 當unquoted分組有匹配內容時,輸出普通值print(f'不帶引號的值: {match.group("unquoted")}')# 輸出邏輯說明:
# 第一個匹配 name=John → 觸發unquoted分組
# 第二個匹配 name="Doe" → 觸發quoted分組(Doe被[^"]+捕獲)

總結:掌握分組技術,提升正則表達式能力 🚀

通過本章學習,我們深入探討了正則表達式的分組與引用技術,包括:

  • 基礎分組:使用 ()創建捕獲組,提取匹配的子串
  • 性能優化:使用 (?:)非捕獲組減少內存占用
  • 可讀性提升:使用命名捕獲組 (?<name>)增強代碼可維護性
  • 高級應用:掌握反向引用、條件表達式等高級技巧

正則表達式的分組技術是處理復雜文本模式的核心工具。熟練掌握這些技巧,能夠讓你輕松解決各種文本處理難題,從簡單的數據提取到復雜的嵌套結構分析。

正則表達式是程序員的瑞士軍刀,而分組技術則是這把軍刀中最鋒利的刀刃之一!🔪

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/89265.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/89265.shtml
英文地址,請注明出處:http://en.pswp.cn/web/89265.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python+requests 接口自動化測試實戰

首先介紹一下python的requests模塊&#xff1a; requests的使用介紹&#xff1a;requests快速入門 Python結合requests庫實現接口自動化測試環境說明&#xff1a; 1.WIN 7, 64位 2.Python3.4.3 &#xff08;pip-8.1.2&#xff09; 3.Requests —>pip install requests 4.U…

NAT 實驗

NAT 實驗 一.實驗拓撲圖實驗目的 1.按照圖示配置 IP 地址 2.私網 A 通過 R1 接入到互聯網&#xff0c;私網 B 通過 R3 接入到互聯網 3.私網 A 內部存在 Vlan10 和 Vlan20&#xff0c;通過 R1 上單臂路由訪問外部網絡 4.私網 A 通過 NAPT 使 Vlan10 和 Vlan20 都能夠使用 R1 的公…

buuctf——web刷題第三頁

第三頁 目錄 [FBCTF2019]RCEService [0CTF 2016]piapiapia [Zer0pts2020]Can you guess it? [WUSTCTF2020]顏值成績查詢 [SUCTF 2019]Pythonginx [MRCTF2020]套娃 [CSCCTF 2019 Qual]FlaskLight [watevrCTF-2019]Cookie Store [WUSTCTF2020]CV Maker [紅明谷CTF 202…

前后端分離項目中的接口設計與調用流程——以高仙機器人集成為例

一、背景介紹在前后端分離項目開發中&#xff0c;前端頁面需要頻繁調用后端接口獲取數據。在高仙機器人對接項目中&#xff0c;我們采用了若依&#xff08;RuoYi&#xff09;框架&#xff0c;前端通過統一的 API 封裝與后端進行數據交互&#xff0c;而后端再對接高仙官方的 OPE…

【第五節】部署http接口到ubuntu server上的docker內

描述清楚需求&#xff0c;讓deepseek幫我們寫一個demo&#xff0c;文件結構如下 FLASK_API_001 ├── app.py └── Dockerfile └── requirements.txtapp.pyfrom flask import Flask, jsonify, requestapp Flask(__name__)# 根路由 app.route(/) def home():return "…

在 IntelliJ IDEA 中添加框架支持的解決方案(沒有出現Add Framework Support)

在 IntelliJ IDEA 中添加框架支持的解決方案 問題背景 版本變化&#xff1a;在 IntelliJ IDEA 2023.2 及更高版本中&#xff0c;項目右鍵菜單中的 “Add Framework Support” 選項已被移除。 常見需求&#xff1a;為 Java 項目添加框架支持&#xff08;如 Maven、Spring 等&am…

北京-4年功能測試2年空窗-報培訓班學測開-第五十天

咦&#xff0c;昨天路上寫一半就到家了&#xff0c;后來想早點睡就忘了還要發了&#xff0c;現在趕緊補上昨天是最后一節課(我們將一整天的課稱為一節&#xff09;&#xff0c;這就結課了昨天講了簡歷編寫&#xff0c;面試要準備的內容&#xff0c;還有redis和docker也沒有什么…

華為鴻蒙HarmonyOpenEye項目:開眼App的鴻蒙實現之旅

華為鴻蒙HarmonyOpenEye項目&#xff1a;開眼App的鴻蒙實現之旅 引言 在當今移動應用開發的浪潮中&#xff0c;鴻蒙系統憑借其獨特的分布式能力和高效的開發框架&#xff0c;吸引了眾多開發者的目光。今天要給大家介紹的是一個基于華為鴻蒙系統開發的開眼App項目——HarmonyO…

代碼隨想錄day36dp4

文章目錄1049.最后一塊石頭的重量II494.目標和474.一和零1049.最后一塊石頭的重量II 題目鏈接 文章講解 class Solution { public:int lastStoneWeightII(vector<int>& stones) {// 1. 確定 DP 數組及下標的含義&#xff1a;// dp[i][j] 表示考慮前 i 塊石頭&#…

Python 爬蟲實戰指南:按關鍵字搜索商品

在電商領域&#xff0c;按關鍵字搜索商品并獲取其詳情信息是一項常見的需求。無論是進行市場調研、競品分析還是用戶體驗優化&#xff0c;能夠快速準確地獲取商品信息都至關重要。1688 作為國內領先的 B2B 電商平臺&#xff0c;提供了豐富的商品資源。本文將詳細介紹如何使用 P…

【源力覺醒 創作者計劃】百度AI的開放新篇章:文心4.5本地化部署指南與未來生態戰略展望

百度AI的開放新篇章&#xff1a;文心4.5本地化部署指南與未來生態戰略展望 一起來玩轉文心大模型吧&#x1f449;文心大模型免費下載地址&#xff1a;https://ai.gitcode.com/theme/1939325484087291906 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30…

測試工作中的質量門禁管理

一、前言 測試階段的質量門禁設計要考慮幾個維度,首先是研發流程的階段劃分,每個階段都要有明確的準入準出標準;其次要考慮不同測試類型的特點,比如功能測試和性能測試的驗收標準肯定不同;最后還要平衡質量要求和項目進度。 在單元測試階段,可以設置通過率和覆蓋率的閾值…

線上分享:解碼eVTOL安全基因,構建安全飛行生態

隨著城市空中交通&#xff08;UAM&#xff09;快速發展&#xff0c;電動垂直起降飛行器&#xff08;eVTOL&#xff09;面臨嚴格的安全與可靠性要求&#xff0c;需滿足全球適航標準及全生命周期分析。安全與可靠的飛行系統成為行業關注的焦點。在此背景下&#xff0c;本期線上分…

C回調函數基礎用法

&#x1f4cc; 定義&#xff1a;回調函數是通過函數指針傳遞給另一個函數的函數&#xff0c;這個被傳進去的函數將在某個時刻被“回調”調用。換句話說&#xff1a;你定義一個函數 A把函數 A 的地址&#xff08;即函數指針&#xff09;作為參數傳給函數 B函數 B 在合適的時機調…

手撕設計模式之消息推送系統——橋接模式

手撕設計模式之消息推送系統——橋接模式 1.業務需求 ? 大家好&#xff0c;我是菠菜啊&#xff0c;好久不見&#xff0c;今天給大家帶來的是——橋接模式。老規矩&#xff0c;在介紹這期內容前&#xff0c;我們先來看看這樣的需求&#xff1a;我們現在要做一個消息推送系統&…

Java 大廠面試題 -- JVM 垃圾回收機制大揭秘:從原理到實戰的全維度優化

最近佳作推薦&#xff1a; Java 大廠面試題 – JVM 面試題全解析&#xff1a;橫掃大廠面試&#xff08;New&#xff09; Java 大廠面試題 – 從菜鳥到大神&#xff1a;JVM 實戰技巧讓你收獲滿滿&#xff08;New&#xff09; Java 大廠面試題 – JVM 與云原生的完美融合&#xf…

圖機器學習(9)——圖正則化算法

圖機器學習&#xff08;9&#xff09;——圖正則化算法1. 圖正則化方法2. 流形正則化與半監督嵌入3. 神經圖學習4. Planetoid1. 圖正則化方法 淺層嵌入方法已經證明&#xff0c;通過編碼數據點間的拓撲關系可以構建更魯棒的分類器來處理半監督任務。本質上&#xff0c;網絡信息…

視頻動態范圍技術演進:從SDR到HDR的影像革命

一、動態范圍技術基礎認知 1.1 人眼視覺特性與動態范圍 人眼的動態感知范圍可達106:1&#xff08;0.0001-105 cd/m&#xff09;&#xff0c;遠超傳統顯示設備能力。視網膜通過虹膜調節&#xff08;物理孔徑&#xff09;與光化學反應&#xff08;光敏蛋白分解&#xff09;實現16…

基于LAMP環境的校園論壇項目

1.配置本地倉庫a.修改主機名為自己姓名全拼[rootserver ~]# hostnamectl set-hostname jun [rootserver ~]# bash [rootjun ~]# 運行結果圖如下圖所示&#xff1a;b.光盤掛載到/mnt目錄下[rootjun yum.repos.d]# mount /dev/sr0 /mnt mount: /mnt: WARNING: source write-prote…

在物聯網系統中時序數據庫和關系型數據庫如何使用?

在物聯網系統中&#xff0c;時序數據庫&#xff08;TSDB&#xff09;和關系型數據庫&#xff08;RDBMS&#xff09;的存儲順序設計需要根據數據特性、業務需求和系統架構綜合考慮。以下是典型的設計方案和邏輯順序&#xff1a;1. 常見存儲順序方案 方案一&#xff1a;先寫時序數…