先講結論:taiwan-id-check 是 25 個 skill 裡唯一完全不連網的——統一編號和身分證字號的檢核碼驗證,純數學,沒有 API、沒有金鑰、沒有資料庫。也所以今天的「實測」沒有 curl,只有 python——然後它抓到了文件自己的驗收建議有問題。
財政部的檢核邏輯:8 碼各乘權重 1,2,1,2,1,2,4,1,乘積的十位數與個位數相加後總和,能被 5 整除即合法。特例:第 7 碼是 7 時,該位貢獻可視為 0 或 1(原本算 10),任一成立即合法。2026-09-30 實測(公開公司統編):台積電 22099131、中華電信 96979933 合法;改動任一碼(22099132)即判非法。
文件寫「台灣大哥大 97176270(第 7 碼 7)只在特例路徑下合法,可驗證特例實作有無」。今天照實測規矩重跑,順手把特例路徑拔掉對照——結果 97176270 在沒有特例的實作下照樣合法:它的加總是 40,本來就能被 5 整除。也就是說這組驗收案例完全不鑑別:特例做沒做,它都過。真正鑑別的案例要滿足「加總 ÷5 餘 4」(特例路徑補 1 才會過),例如 10000073:加總 14,無特例判非法、有特例判合法。2026-09-30 實測對照:
| 測資 | 加總 | 無特例實作 | 有特例實作 |
|---|---|---|---|
| 97176270 | 40 | 合法 | 合法(不鑑別) |
| 10000073 | 14 | 非法 | 合法(鑑別成功) |
文件的檢核邏輯沒錯,但驗收建議選錯了測資——這就是為什麼「實測過才收錄」連驗收案例本身都要實測。
def ubn_ok(n: str) -> bool:
if len(n) != 8 or not n.isdigit():
return False
w = [1, 2, 1, 2, 1, 2, 4, 1]
ds = lambda p: p // 10 + p % 10 # 乘積的各位數和
base = sum(ds(int(d) * k) for d, k in zip(n, w))
if base % 5 == 0:
return True
if n[6] == '7': # 第 7 碼 7 的特例
c = ds(7 * 4)
return (base - c + 0) % 5 == 0 or (base - c + 1) % 5 == 0
return False
依據:財政部營利事業統一編號檢查邏輯(明文規定第 7 碼 7 的特例);文件正本是 repo 的 taiwan-id-check/SKILL.md。
內政部規則:首字母依對照表轉兩位數(A=10 起,但 I=34、O=35、W=32、X=30、Y=31、Z=33,跳過容易混淆的順序),十位乘 1、個位乘 9;後 8 碼依序乘 8,7,6,5,4,3,2,1,檢核碼乘 1,總和能被 10 整除即合法。經典測試值 A123456789、B221003265 實測合法,末碼改動即非法。
這個 skill 的邊界要講得很硬:它只回答「這串號碼的檢核碼對不對」,不回答「這家公司存不存在」。統編對不對請去財政部稅籍登記公示查詢;身分證檢核碼可以計算,不等於實際核發。檢核不符最常見的原因是打錯字,回報用語就是「檢核碼不符」,不做法律判斷。
第 23 天。25 個 skill 裡唯一不用網路的這個,反而最能把「實測」兩個字做到底——今天連文件自己的驗收案例都被實測抓出來。