正規表達式 (Regex) 駝峰切詞與特例保護教學; (?i: … ):不分大小寫的非捕獲群組

加入好友
加入社群
正規表達式 (Regex) 駝峰切詞與特例保護教學; (?i: … ):不分大小寫的非捕獲群組 - 儲蓄保險王

我們的目標是將極端不規則的 class_name (例如 IPMIBMC_Check_PCIeNVMe),乾淨且精準地拆解成 [‘IPMI’, ‘BMC’, ‘Check’, ‘PCIe’, ‘NVMe’]。

由於傳統的 \w+ 會把整串黏在一起,而標準的駝峰拆分會把 PCIe 切壞變成 PC, Ie。為了解決這個問題,我們設計了一套由左至右、特例優先 (Exceptions First) 的雙層 Regex 引擎。

示範 Python Code
你可以直接執行這段程式碼來體驗切割效果:

import re

# 1. 專有名詞例外清單 (Exceptions)
# 這些詞必須被完整保護」,不能被後面的駝峰規則切碎
exceptions = [
    r'NVMe', r'PCIe', r'I2c', r'VGA', r'IPMI', r'BMC', r'Sensor', r'list'
]

# 2. 定義不分大小寫的群組外衣: 變成 (?i:NVMe|PCIe|I2c|VGA|IPMI|BMC|Sensor|list)
exceptions_joined_str = '|'.join(exceptions)
regex_wrapper_start = r'(?i:'  # (?i: 代表這個小括號內的所有東西都不分大小寫
regex_wrapper_end = r')'
exceptions_pattern = regex_wrapper_start + exceptions_joined_str + regex_wrapper_end

# 3. 基礎主引擎 (負責處理常規的駝峰連寫大寫數字)
# 這裡用到 Lookahead 前瞻判斷 (?=...)
base_pattern = r'[A-Z]?[a-z]+|[A-Z]+(?=[A-Z][a-z]|\d|\W|_|$)|\d+'

# 4. 組合最終兵器: 先配對例外 (| 前面),若沒中再進入主引擎 (| 後面)
camel_case_pattern = re.compile(exceptions_pattern + r'|' + base_pattern)

# ===== 測試環節 =====
test_cases = [
    "NVMeVGAAutoProcess_Step",
    "Sensor_list_TestPCIe",
    "IPMIBMC_Check"
]

for cls_name in test_cases:
    tokens = camel_case_pattern.findall(cls_name)
    print(f"原始字串: {cls_name}")
    print(f"切割結果: {tokens}")
    print("-" * 40)

輸出結果:

正規表達式 (Regex) 駝峰切詞與特例保護教學; (?i: … ):不分大小寫的非捕獲群組 - 儲蓄保險王

語法細節拆解:為什麼這樣寫可以切開?

  1. (?i: … ):不分大小寫的非捕獲群組
    (?: … ) 是一種把條件綁在一起,但是不輸出多餘結果的括號。
    加上 i 變成 (?i: … ),代表裡面放的 NVMe|PCIe,不管來源寫成 nvme, NVME, Nvme 都能被完美命中。
  2. Regex 引擎的「由左至右法則」
    我們最後將條件合併為 特例規則 | 主引擎規則。
    當遇到字串 “TestPCIe” 時,引擎的掃描順序是:

掃到 Test。它不符合例外清單,所以進入主引擎,被切出來。
剩下 PCIe。引擎掃描時發現它命中了左邊的例外清單! 於是直接整塊抽走,成功避開了進入右邊主引擎被切碎的命運。這就是「特例保護網」的機制。
3.主引擎 base_pattern 詳細分析

r'[A-Z]?[a-z]+ | [A-Z]+(?=[A-Z][a-z]|\d|\W|_|$) | \d+'

這段被 | 切成三個主要的攻擊火力:

攻擊 A:[A-Z]?[a-z]+
這負責最常見的命名。

[A-Z]?:有沒有大寫開頭都可以 (例如 P 或沒有)。
[a-z]+:後面一定要接至少一個小寫的單字。
效果:它會把 Process, Step, auto, list 等詞全部抓出來。
攻擊 B:[A-Z]+(?=[A-Z][a-z]|\d|\W|_|$) (連續大寫對策)
這負責處理 VGAAuto 這種連續大寫縮寫接上一般單字的狀況,要怎麼知道在哪裡能切斷?

[A-Z]+:貪婪地抓取連在一起的大寫字母 (抓到 VGAA)。
(?= … ):這叫正向先行斷言 (Lookahead)。它的意思是:「我想切斷,但我得先『偷看』下一個字元符合不符合規矩,符合我才切。」而且偷看的部分不會被消耗掉,留給下一輪使用。
偷看的條件有很多:

[A-Z][a-z]:如果下一個出現的是「大寫接小寫」(這就是為什麼 VGAAuto 抓到 VGA 時,看到偷看的字是 Au,就在 A 前面果斷切斷的原因)。
\d:如果下一個是數字也切斷。
\W:非單字字元也切斷(例如空格)。注意:\w 是包含 [a-zA-Z0-9_] 的,所以 \W (大寫) 是排除它們,也就是說 \W 漏掉了底線。
:這就是你特別提到的重點。因為 \W 沒有涵蓋底線,如果字串是 SENSOR_LIMIT,它會不知道該停下來。所以我們必須手動在看前方的條件補上 ,告訴引擎「看到下一個字元是底線,也要停下來切斷」。
$:或者是已經到了字尾。
攻擊 C:\d+
針對不管在哪裡出現的純數字串 (諸如版本號 2 或 101),把它獨立拔出來。

小結:任何不屬於我們規則裡面 (不是英文字母也不是數字) 的符號,例如底線 _ 或是空格,都會被正規表達式默默地「跳過」,我們便得到了一份非常乾淨且符合測試領域語意的 Token 陣列!

推薦hahow線上學習python: https://igrape.net/30afN

加入好友
加入社群
正規表達式 (Regex) 駝峰切詞與特例保護教學; (?i: … ):不分大小寫的非捕獲群組 - 儲蓄保險王

儲蓄保險王

儲蓄險是板主最喜愛的儲蓄工具,最喜愛的投資理財工具則是ETF,最喜愛的省錢工具則是信用卡

You may also like...

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *