fix(migrate-wiki): 候選鍵兼收條列與表格兩種目錄頁形狀

搬頁時蒐集候選鍵的那一段,原本只讀目錄頁表格的存取庫、主機、帳號、工具、
期間五欄。現在改成 H2 區塊底下的「- {欄位名}:{值}」也照樣讀,表格的欄位
維持原樣收下,兩種形狀都認得。

目錄頁已經改成條列,還沒轉檔的線上舊頁卻仍是表格,同一輪搬頁會同時遇到
兩種。只讀表格的話,條列頁一個候選鍵都收不到,那些頁的舊頁名就對不到新
頁名,搬頁會把它們當成沒有對應而漏掉。

讀取改成逐行判斷:碰到「## 」就把上一個區塊收掉並開新的一筆,區塊內的
條列按欄位名對照收值。欄位值各自算一個候選鍵,再依固定欄位順序串一個組合
鍵,跟表格那一路的產出規則完全一致。條列的冒號正本寫全形,半形也一併收,
舊頁手寫的那幾條才不會整條漏掉。

功能範圍:目錄頁版面改版的搬頁相容。
This commit is contained in:
2026-09-02 17:22:24 +08:00
parent c7c14445e6
commit 9942cf2506
+49 -7
View File
@@ -14,7 +14,9 @@
# --key 可重複,補充自動蒐集不到的候選鍵。 # --key 可重複,補充自動蒐集不到的候選鍵。
# #
# 候選鍵來源: # 候選鍵來源:
# 目錄頁表格的存取庫、主機、帳號、工具、期間欄,以及這幾欄依序串成的組合鍵。 # 目錄頁每一筆的存取庫、主機、帳號、工具、期間,以及這幾項依序串成的組合鍵。
# 目錄頁是 H2 區塊加條列的形狀,所以讀「- {欄位名}:{值}」那幾條;還沒轉檔的舊頁
# 仍是 markdown 表格,所以表格的欄位也照樣讀,兩種形狀都收。
# 內容頁的 H1 標題(CHECK 頁的 H1 直接就是 {主機}/{帳號})。 # 內容頁的 H1 標題(CHECK 頁的 H1 直接就是 {主機}/{帳號})。
# --key 補充的候選。 # --key 補充的候選。
# #
@@ -136,7 +138,7 @@ for ty in $TYPES; do
done done
# ---- 第二輪:蒐集候選鍵 ---- # ---- 第二輪:蒐集候選鍵 ----
# 目錄頁表格的欄位值,以及依序串成的組合鍵 # 目錄頁每一筆的欄位值,以及依序串成的組合鍵
while IFS="$TAB" read -r orepo opage nrepo npage <&3; do while IFS="$TAB" read -r orepo opage nrepo npage <&3; do
[ -n "$opage" ] || continue [ -n "$opage" ] || continue
case "$opage" in *_CONTENTS) ;; *) continue ;; esac case "$opage" in *_CONTENTS) ;; *) continue ;; esac
@@ -174,9 +176,49 @@ def plain(v):
idx = {} idx = {}
seen_sep = False seen_sep = False
out = [] out = []
block = None
def take(found):
"""一筆紀錄收到的欄位值,各自算一個候選鍵,依 WANT 順序再串一個組合鍵。"""
if not found:
return
parts = []
for w in WANT:
v = found.get(w)
if not v:
continue
out.append(v)
parts.append(v)
if len(parts) > 1:
out.append('/'.join(parts))
for line in lines: for line in lines:
# 目錄頁一筆一個 H2 區塊,欄位在標題底下一條一條列。
if line.startswith('## '):
take(block)
block = {}
idx, seen_sep = {}, False
continue
cs = cells(line) cs = cells(line)
if cs is None: if cs is None:
if block is not None:
s = line.strip()
if s.startswith('- '):
body = s[2:]
# 正本寫全形冒號;半形也收,舊頁手寫的那幾條才不會整條漏掉。
for mark in (':', ':'):
if mark in body:
label, value = body.split(mark, 1)
label = plain(label)
for w in WANT:
if w in label:
v = plain(value)
if v:
block[w] = v
break
break
idx, seen_sep = {}, False idx, seen_sep = {}, False
continue continue
if is_sep(cs): if is_sep(cs):
@@ -193,7 +235,7 @@ for line in lines:
continue continue
if not idx: if not idx:
continue continue
parts = [] found = {}
for w in WANT: for w in WANT:
i = idx.get(w) i = idx.get(w)
if i is None or i >= len(cs): if i is None or i >= len(cs):
@@ -201,10 +243,10 @@ for line in lines:
v = plain(cs[i]) v = plain(cs[i])
if not v: if not v:
continue continue
out.append(v) found[w] = v
parts.append(v) take(found)
if len(parts) > 1:
out.append('/'.join(parts)) take(block)
for v in out: for v in out:
print(v) print(v)