File size: 1,519 Bytes
6cc3500 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | """保護段:把必須 byte-exact 保留的片段換成 PUA 佔位符,最後再還原。
由 V1 的 runtime.py 抽出成獨立模組,讓 V3 推論路徑不必匯入 V1
(V1 需要 yaml、sites.yaml、model.py,在 pip/HF 環境是多餘的相依)。
"""
from __future__ import annotations
import re as _re
# URL 的字元集必須明列,不能用 \S+:中文後面沒有空白分隔,
# \S+ 會把「…id=972,最后浏览日期…」整段吞進 copy buffer,
# 那段中文就完全繞過後續處理、簡體原樣輸出(實測過的真實 bug)。
COPY_EXACT = _re.compile(
r"https?://[A-Za-z0-9\-._~:/?#\[\]@!$&'()*+;=%]+"
r"|[A-Za-z0-9][\w.+-]*@[\w-]+(?:\.[\w-]+)*\.[A-Za-z]{2,}" # Email
r"|`[^`]+`" # inline code
r"|```[\s\S]*?```" # code fence
r"|\bv?\d+\.\d+(?:\.\d+)*(?:-[\w.]+)?\b" # 版本號
r"|\bgit@[\w.-]+:[\w./-]+" # git remote
)
PUA_BASE = 0xE000
PUA_MAX = 0xF8FF
def protect(text: str) -> tuple[str, list[str]]:
saved: list[str] = []
def sub(m):
if len(saved) >= PUA_MAX - PUA_BASE:
return m.group(0)
saved.append(m.group(0))
return chr(PUA_BASE + len(saved) - 1)
return COPY_EXACT.sub(sub, text), saved
def restore(text: str, saved: list[str]) -> str:
if not saved:
return text
return "".join(
saved[ord(c) - PUA_BASE] if PUA_BASE <= ord(c) < PUA_BASE + len(saved)
else c for c in text)
|