處理大型文字檔案時,逐詞迭代比一次性載入更記憶體友善。本文展示三種遞進式方案:基本切分、正則強化、生成器封裝,並解決常見編碼與效能陷阱。
str.split() 逐行逐詞
import codecs
with codecs.open('d:/text.txt', 'r', 'utf-8') as f:
for line in f:
for word in line.split():
print(word, end='|')
print()
缺點:split() 僅按空白字元切分,標點符號會殘留在詞中(如 "hello,")。
用 re.finditer 依規則萃取「單字」,支援 Unicode、連字號、縮寫等:
import re, codecs
WORD_RE = re.compile(r"[\w'-]+", re.UNICODE) # 字母數字底線、連字號、單引號
with codecs.open('d:/text.txt', 'r', 'utf-8') as f:
for line in f:
for m in WORD_RE.finditer(line):
print(m.group(0), end='|')
print()
[\w'-]+ 可匹配 don't、mother-in-law、Python3 等。
核心模式:外層生成器逐行讀取 → 內層生成器逐詞產出 → yield from 或雙層 for 扁平化。
import codecs, re
def words_of_file(filepath, line_to_words=str.split):
"""通用逐詞生成器:接受自訂切詞函數"""
with codecs.open(filepath, 'r', 'utf-8') as f:
for line in f:
for word in line_to_words(line):
yield word
def words_by_re(filepath, pattern=r"[\w'-]+"):
"""正則版逐詞生成器"""
word_re = re.compile(pattern, re.UNICODE)
def line_to_words(line):
for m in word_re.finditer(line):
yield m.group(0)
return words_of_file(filepath, line_to_words)
# 使用範例
for w in words_of_file('d:/text.txt'):
print(w, end='|')
print()
for w in words_by_re('d:/text.txt'):
print(w, end='|')
with 區塊:確保檔案正確關閉,即使發生例外。encoding='utf-8':Python 3 開檔預設即為 UTF-8,codecs.open 可改為內建 open。readlines():大檔案會佔滿記憶體,逐行迭代才是正解。re.compile 避免重複編譯開銷。
# 使用 mmap 實現零拷貝讀取(需二進位模式)
import mmap, re
WORD_RE = re.compile(rb"[\w'-]+")
def mmap_words(filepath):
with open(filepath, 'rb') as f:
with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as mm:
for m in WORD_RE.finditer(mm):
yield m.group(0).decode('utf-8')
掌握生成器模式,能優雅地處理 GB 級文字資料,同時保持程式碼清晰可測試。