解析 re.findall(r"|<[^>]*>|[\w'@#]+", str.lower()) 的匹配邏輯,指出原寫法缺陷,給出優化版本並解釋各組件含義。
r"|<[^>]*>|[\w'@#]+"
問題: 開頭的 | 導致第一個選項為空字符串,會匹配任意位置的空串,產生大量無意義空結果。
r"(<[^>]*>|[\w'@#]+)"
用捕獲組 (...) 包裹整體,移除開頭多餘的 |。
| 片段 | 含義 | 匹配示例 |
|---|---|---|
( ... ) | 捕獲組,findall 返回組內容而非整個匹配 | - |
<[^>]*> | HTML 標籤:< + 非 > 字符任意數 + > | <div>, <a href="#"> |
| | 或運算符 | - |
[\w'@#]+ | 單詞字符(字母數字下劃線)+ 單引號 + @ + #,一或多個 | hello, user@domain, #tag |
str.lower():字符串轉小寫re.findall(pattern, string):掃描字符串,找到所有不重疊匹配
import re
text = "Hello @user #python
"
pattern = r"(<[^>]*>|[\w'@#]+)"
result = re.findall(pattern, text.lower())
print(result)
# 輸出: ['', 'hello', '@user', '#python', '
']
# 錯誤:<[^>]*> 在 text
more 中會匹配整個 text
more
# 修正:非貪婪 <[^>]*?> 或 精確 <[^>]+>
r"(<[^>]*?>|[\w'@#]+)"
# 在字符類 [] 中,^ - ] \ 需轉義或放安全位置
# 原寫法 [\w'@#] 正確,若加入 ] 需寫 [\w'@#\]] 或 []\w'@#]
# 必須使用 r"" 避免 \ 被 Python 字符串轉義
# 否則 \w 會變成無意義的轉義序列
pattern = r"(?P<[^>]*>)|(?P[\w'@#]+)"
for m in re.finditer(pattern, text.lower()):
if m.group('tag'):
print(f"標籤: {m.group('tag')}")
else:
print(f"詞元: {m.group('word')}")
pattern = re.compile(r"(<[^>]*>|[\w'@#]+)")finditer 迭代器避免一次性構建巨大列表BeautifulSoup/lxml,正則不適合處理巢狀結構原表達式開頭多餘的 | 導致空匹配污染結果。優化版 r"(<[^>]*>|[\w'@#]+)" 正確提取 HTML 標籤與特定詞元。實際項目中:預編譯、用原始字符串、複雜結構改用專用解析器。