Python 正則表示法 中 ?: 與(非)捕獲群組的精要筆記(含程式例子); ? 的多重語義:量詞0 or 1次, +?非貪婪量詞, ?!非捕獲群組, ?P<name> 命名捕獲組, ?=斷言

加入好友
加入社群
Python 正則表示法 中 ?: 與(非)捕獲群組的精要筆記(含程式例子); ? 的多重語義:量詞0 or 1次, +?非貪婪量詞, ?!非捕獲群組, ?P<name> 命名捕獲組, ?=斷言 - 儲蓄保險王

1. 群組 vs. 捕獲群組 vs. 非捕獲群組

群組 (group): 用括號把子表達式包起來以便「成為一個單位」(重複、選擇、優先順序)。
捕獲群組 (capturing group): (…) 會把匹配內容存進 group 編號/名稱,供 group(1)/groupdict() 取用。
非捕獲群組 (non‑capturing group): (?:…) 只做「分組」但不建立群組結果,避免影響編號。
為什麼需要非捕獲群組?

不想要內容被取出(純粹為了分組或量詞/優先順序)。
不想讓群組編號改變(減少「編號漂移」帶來的維護痛苦)。
findall 行為更直覺(不會因為多了捕獲群組而回傳 tuple)。

Python 正則表示法 中 ?: 與(非)捕獲群組的精要筆記(含程式例子); ? 的多重語義:量詞0 or 1次, +?非貪婪量詞, ?!非捕獲群組, ?P<name> 命名捕獲組, ?=斷言 - 儲蓄保險王

2. ? 的多重語義

Python 正則表示法 中 ?: 與(非)捕獲群組的精要筆記(含程式例子); ? 的多重語義:量詞0 or 1次, +?非貪婪量詞, ?!非捕獲群組, ?P<name> 命名捕獲組, ?=斷言 - 儲蓄保險王

3. 經典數字範式:(\d+(?:\.\d+)?)

Python 正則表示法 中 ?: 與(非)捕獲群組的精要筆記(含程式例子); ? 的多重語義:量詞0 or 1次, +?非貪婪量詞, ?!非捕獲群組, ?P<name> 命名捕獲組, ?=斷言 - 儲蓄保險王

好處:小數部分用非捕獲群組,避免 findall 回傳 tuple。

對比看看 捕獲群組版本

Python 正則表示法 中 ?: 與(非)捕獲群組的精要筆記(含程式例子); ? 的多重語義:量詞0 or 1次, +?非貪婪量詞, ?!非捕獲群組, ?P<name> 命名捕獲組, ?=斷言 - 儲蓄保險王

👉 很容易多出 tuple,處理上比較麻煩。


4. 命名捕獲群組

Python 正則表示法 中 ?: 與(非)捕獲群組的精要筆記(含程式例子); ? 的多重語義:量詞0 or 1次, +?非貪婪量詞, ?!非捕獲群組, ?P<name> 命名捕獲組, ?=斷言 - 儲蓄保險王

5. Lookaround 斷言

Python 正則表示法 中 ?: 與(非)捕獲群組的精要筆記(含程式例子); ? 的多重語義:量詞0 or 1次, +?非貪婪量詞, ?!非捕獲群組, ?P<name> 命名捕獲組, ?=斷言 - 儲蓄保險王

6. findall 的差異

Python 正則表示法 中 ?: 與(非)捕獲群組的精要筆記(含程式例子); ? 的多重語義:量詞0 or 1次, +?非貪婪量詞, ?!非捕獲群組, ?P<name> 命名捕獲組, ?=斷言 - 儲蓄保險王

7. 實務範例:抓評分(含 fallback)

Python 正則表示法 中 ?: 與(非)捕獲群組的精要筆記(含程式例子); ? 的多重語義:量詞0 or 1次, +?非貪婪量詞, ?!非捕獲群組, ?P<name> 命名捕獲組, ?=斷言 - 儲蓄保險王

或者 三層try~ except~:


def gpt_similarity(text1, text2=user_query):
    """
    用GPT判斷兩段文字的相似
    try: 使用re.search分離出整數(浮點數)部分
    except: 若捕捉到例外,
        再try: re.split()
        except: 要是又有例外,
            try:使用GPT只輸出數字部分,三層的try~ except~
    """
    prompt_compair = f"""
    請判斷以下兩段話的語意關聯性1~10並且務必只輸出以下格式
    語意關聯性評分X分

    第一段: {text1}
    第二段: {text2}
    """
    response = client_LLM.chat.completions.create(
        model=model_LLM,
        messages=[
            {"role": "user", "content": prompt_compair}
        ]
    )
    content = response.choices[0].message.content
    # '語意關聯性評分:9分'
    # pattern = r"語意關聯性評分[::]\s*(\d+)分" #簡單版,假設X為整數
    pattern = r"語意關聯性評分[::]\s*(\d+(?:\.\d+)?)\s*分" #連小數點都會捕抓
    """
    (?:\.\d+)?
    (\d+(?:\.\d+)?) 中的 (?:\.\d+)?:

    這裡有兩個?但功能不同

    (?: ... ) 裡面的?:非捕獲群組的語法記號
    不是量詞它只代表分組但不產生 group 編號」。

    末尾的「)?這個?才是量詞表示整個群組可有可無0  1 )」。

    所以 (?:\.\d+)? 的意思是

    非捕獲群組 (?:\.\d+):一個小數點 + 至少一位數字

    後面的 ?讓這整段小數部分變成可選(0  1 )

    等價寫法用捕獲群組也行):

    (\.\d+)? 也是小數部分可選
    """

    try:
        match = re.search(pattern, content)
        #<re.Match object; span=(0, 10), match='語意關聯性評分:9分'>
        return float(match.group(1))
        #match.group(0) #'語意關聯性評分:9分'
        #match.group(1) #'9'
    except:
        try:
            #有辦法轉為 float  元素就return
            parts = re.split(":|:|分", content)
            parts = re.split(r"[::分]\s*", content) #順便吃掉後面的空白
            # re.split(":|:|分", content)
            #['語意關聯性評', '', '9', '']
            for p in parts:
                try:
                    return float(p.strip().replace("","."))  
                    # 嘗試轉換成浮點數
                except ValueError:
                    continue
 
        except:
            try:
                prompt2 = f"請對以下內容,只輸出數字部分:{content}"
                response = client_LLM.chat.completions.create(
                    model=model_LLM,
                    messages=[
                        {"role": "user", "content": prompt2}
                    ]
                )
                content2 = response.choices[0].message.content
                return float(content2.strip())
            except ValueError:
                    return 0.0

✅ 小結

  • ( … ) = 捕獲群組,(?: … ) = 非捕獲群組,不影響 group 編號。
  • ? 在不同位置代表 可選 / 非貪婪 / 群組前綴,要分清楚。
  • 數字模式常用 (\d+(?:\.\d+)?),避免多餘的 tuple。
  • findall 的行為強烈受捕獲群組影響 → 不想要 tuple 就用 (?:…)
  • 命名群組 (?P<name>…) 與 lookaround (?=…) 等技巧能讓正則更可讀、更穩定。

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

是否為捕獲組,主要影響 re.findall(),
re.search() 影響不大

1. re.search()

  • 會回傳一個 Match 物件
  • 你要什麼內容 → 用 .group(n).group('name') 去取。
  • 所以 有沒有捕獲群組,只是影響你 .group() 能取到什麼,不會改變回傳 Match 物件本身

例子:

Python 正則表示法 中 ?: 與(非)捕獲群組的精要筆記(含程式例子); ? 的多重語義:量詞0 or 1次, +?非貪婪量詞, ?!非捕獲群組, ?P<name> 命名捕獲組, ?=斷言 - 儲蓄保險王

👉 search() 的行為沒有變,差別只是你能不能 .group(1)


2. re.findall()

  • 回傳的是「匹配結果的清單」。
  • 如果 pattern 裡有捕獲群組 → 只回傳捕獲內容(如果有多個群組,會變 tuple)。
  • 如果沒有捕獲群組 → 回傳整個匹配字串。

例子:

Python 正則表示法 中 ?: 與(非)捕獲群組的精要筆記(含程式例子); ? 的多重語義:量詞0 or 1次, +?非貪婪量詞, ?!非捕獲群組, ?P<name> 命名捕獲組, ?=斷言 - 儲蓄保險王

✅ 結論

  • search():回傳的是 Match 物件 → 捕獲群組只是決定你能不能 .group(n),不會影響回傳型態。
  • findall():回傳的是 list → 捕獲群組會直接影響回傳結構(字串 or tuple)。

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

加入好友
加入社群
Python 正則表示法 中 ?: 與(非)捕獲群組的精要筆記(含程式例子); ? 的多重語義:量詞0 or 1次, +?非貪婪量詞, ?!非捕獲群組, ?P<name> 命名捕獲組, ?=斷言 - 儲蓄保險王

儲蓄保險王

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

You may also like...

發佈留言

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