攝影或3C

Python: 如何使用正則表示法(Regular Expression)非貪婪模式(.*?) or (.+?),取出以下字串所有被雙引號包圍的部分?response: addr=”0000:01:00.0″ vid=”0x144d” did=”0xa826″ svid=”0x144d” sid=”0xab4c” speed=”16.0GT/s” width=”x4″ max_width=”x4″ expected_width=”x4″ expected_speed=”16.0GT/s” devpath=”/phys/SB_CAB0/DOWNLINK/U2_15:device:nvme:nvme”

code

# -*- coding: utf-8 -*-
"""
Created on Sun Dec 23 19:37:18 2024

@author:SavingKing
"""

import re
from typing import List, Tuple
from collections import namedtuple

text = """response: 
addr="0000:01:00.0" vid="0x144d" did="0xa826" svid="0x144d" sid="0xab4c" speed="16.0GT/s" width="x4" max_width="x4" expected_width="x4" expected_speed="16.0GT/s" devpath="/phys/SB_CAB0/DOWNLINK/U2_15:device:nvme:nvme"
更多设备信息...)"""

pattern = r"addr=\"(.*?)\" vid=\"(.*?)\" did=\"(.*?)\" svid=\"(.*?)\" sid=\"(.*?)\" speed=\"(.*?)\" width=\"(.*?)\" max_width=\"(.*?)\" expected_width=\"(.*?)\" expected_speed=\"(.*?)\" devpath=\"(.*?)\""
PCIeList = namedtuple("PCIeList", ["addr", "vid", "did", "svid", "sid", "speed", "width", "max_width", "expected_width", "expected_speed", "devpath"])
matches: List[Tuple[str]] = re.findall(pattern, text)
print("matches:\n", matches)

lis_namedtuple: List[namedtuple] = []
for match in matches:
    nt = PCIeList(*match)  # 使用 *match 来解包元组
    lis_namedtuple.append(nt)

# 打印创建的 namedtuple 列表以验证
for item in lis_namedtuple:
    print("\nnamedtuple:\n",item)

輸出結果:

輸出結果:

matches:
 [('0000:01:00.0', '0x144d', '0xa826', '0x144d', '0xab4c', '16.0GT/s', 'x4', 'x4', 'x4', '16.0GT/s', '/phys/SB_CAB0/DOWNLINK/U2_15:device:nvme:nvme')]

namedtuple:
 PCIeList(addr='0000:01:00.0', vid='0x144d', did='0xa826', svid='0x144d', sid='0xab4c', speed='16.0GT/s', width='x4', max_width='x4', expected_width='x4', expected_speed='16.0GT/s', devpath='/phys/SB_CAB0/DOWNLINK/U2_15:device:nvme:nvme')

匹配的文字:

"""response: 
addr="0000:01:00.0" vid="0x144d" did="0xa826" svid="0x144d" sid="0xab4c" speed="16.0GT/s" width="x4" max_width="x4" expected_width="x4" expected_speed="16.0GT/s" devpath="/phys/SB_CAB0/DOWNLINK/U2_15:device:nvme:nvme"
更多设备信息..."""

正則表達式(Regular Expression):

pattern = r"addr=\"(.*?)\" vid=\"(.*?)\" did=\"(.*?)\" svid=\"(.*?)\" sid=\"(.*?)\" speed=\"(.*?)\" width=\"(.*?)\" max_width=\"(.*?)\" expected_width=\"(.*?)\" expected_speed=\"(.*?)\" devpath=\"(.*?)\""

在正則表達式中,(.*?) 是一個非常重要的模式,它用來進行非貪婪(或最小)匹配。以下是這個模式各部分的詳細解釋:

模式 .
. 是正則表達式中的一個特殊字符,它用於匹配任何單個字符(除了換行符)。
模式 *
代表前面的字符(在這種情況下是任意字符 .)可以出現零次或多次。它是一個量詞,用來指定前一個元素可以重覆的次數。
模式 +
代表前面的字符(在這種情況下是任意字符 .)可以出現一次或多次。它是一個量詞,用來指定前一個元素可以重覆的次數。
模式 ?
當 ? 緊跟在 * (0次以上)或 +(1次以上) 後面時,它將匹配模式轉變為非貪婪模式。默認情況下,* 和 + 是貪婪的,它們會盡可能多地匹配文本。加上 ? 後,匹配會盡可能少地滿足模式。
在這個上下文中, 讓 .*(匹配任意數量的任意字符)變成 .*?,意味著它會進行最小量的匹配直到滿足條件為止。
非貪婪匹配模式
當你在 * 或 + 後面添加一個問號 ?,它會改變量詞的行為,從貪婪模式轉變為非貪婪模式。這意味著正則表達式會盡可能少地匹配字符。實際使用中,這通常用於需要精確定位結束點的場景:

*? 表示“零次或多次”,但盡可能少地匹配。
+? 表示“一次或多次”,但盡可能少地匹配。
模式 ()
圓括號 () 在正則表達式中用於分組。分組可以用於多個目的:
提取信息:當正則表達式與字符串匹配時,你可以從字符串中提取出圓括號內的模式匹配到的部分。
指定操作範圍:圓括號內的部分可以作為一個整體進行量詞操作或其他正則表達式操作。

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

假設我們有一個字符串:

"<tag>hello</tag><tag>world</tag>"

我們想提取每個

<tag> </tag>

中間的內容。

使用貪婪模式 “.*“,正則表達式會匹配從第一個

 <tag>

到最後一個

 </tag>

之間的全部內容,即

 "hello</tag><tag>world"

使用非貪婪模式 “.*?”,正則表達式會分別匹配每一對

 <tag>

 </tag>

之間的內容,即先匹配 “hello”,然後匹配 “world”。

# -*- coding: utf-8 -*-
"""
Created on Mon Dec 23 21:02:21 2024

@author: SavingKing
"""

import re

# 定義一個包含嵌套 <tag> 的字符串
text = "<tag>hello</tag><tag>world</tag>"

# 貪婪模式正則表達式
greedy_pattern = "<tag>(.*)</tag>"
# 非貪婪模式正則表達式
nongreedy_pattern = "<tag>(.*?)</tag>"

# 使用貪婪模式進行匹配
greedy_match = re.findall(greedy_pattern, text)
# 使用非貪婪模式進行匹配
nongreedy_match = re.findall(nongreedy_pattern, text)

# 打印結果
print("Greedy match:", greedy_match)
print("Non-greedy match:", nongreedy_match)

輸出結果:

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

# -*- coding: utf-8 -*-
"""
Created on Mon Dec 23 21:48:58 2024

@author: SavingKing
"""

import re

text = """response: 
addr="0000:01:00.0" vid="0x144d" did="0xa826" svid="0x144d" sid="0xab4c" speed="16.0GT/s" width="x4" max_width="x4" expected_width="x4" expected_speed="16.0GT/s" devpath="/phys/SB_CAB0/DOWNLINK/U2_15:device:nvme:nvme"
更多設備信息..."""

# 正則表達式改為匹配鍵和
pattern = re.compile(r'(\w+)="(.*?)"')

# 使用 findall() 方法提取所有匹配的鍵值對
matches = pattern.findall(text)

# 打印所有匹配的鍵值對
for key, value in matches:
    print(f'{key}: {value}')

輸出結果:

matches:

正則表達式解釋
(\w+):捕獲一個或多個字母、數字或下劃線的序列作為鍵名。
=”(.?)”:匹配等號後跟著雙引號內的任意字符序列,直到遇到第一個閉合的雙引號。使用非貪婪匹配(?)確保只捕獲到第一個閉合雙引號之前的內容。
這個正則表達式將正確地識別並提取每個鍵值對,如 addr 對應 “0000:01:00.0″,vid 對應 “0x144d” 等等。這種方法把鍵和值都整潔地提取出來,適用於解析類似格式的字符串數據。

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

\w 字符類的定義
在正則表達式中,\w 是一個非常常用的字符類,它代表“word character”(單詞字符),通常包括:

所有字母(包括大小寫),即 a-z 和 A-Z
所有數字,即 0-9
下劃線 _
因此,當你看到 \w,可以認為它等價於 [a-zA-Z0-9_]。

使用 \w 的場景
\w 非常適合用於匹配標識符、變量名、代碼中的對象屬性等,因為這些元素通常只由字母、數字和下劃線組成。例如:

在編程語言中,變量名通常遵循這樣的命名規則。
在許多應用程序的配置文件中,鍵(key)名稱也遵循類似的命名規則。
示例
考慮到 \w 的這些特點,如果我們回到之前的正則表達式使用場景中,使用 (\w+)=”(\w?)” 對於某些數據可能就顯得過於嚴格。例如,如果配置值包含路徑或包含特殊字符的字符串(/ or :),這樣的正則表達式就無法匹配它們。這就是為什麽通常推薦使用更為靈活的表達式如 (\w+)=”(.*?)”,它可以匹配包括空格和特殊字符在內的更廣泛的字符集。

注意事項
\w 的行為可能略有不同,取決於正則表達式的實現和應用的編程語言。例如,在某些語言或庫中,\w 可能還包括其他Unicode字符,特別是涉及非英語字符集時。
在某些環境中,使用 \w 時需要注意語言或庫是否支持 Unicode 字符類,否則可能不會按預期匹配非英語字母。
總之,\w 是一個非常實用的正則表達式構建塊,用於匹配單詞字符。它在處理文本和生成可用於各種編程和腳本任務的模式時非常有用。。

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

儲蓄保險王

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