條碼驗證參考

Item Master 專案的條碼品質控管參考文件。 涵蓋格式驗證、GS1 prefix 判讀、常見誤判模式與大規模驗證流程。


1. 條碼格式總覽

格式 位數 結構 常見場景
EAN-13 13 PPP MMMM IIIII C 台灣與多數零售商品主流
EAN-8 8 PPPP IIIC 小型包裝
UPC-A 12 S MMMMM IIIII C 北美商品,可前補 0 轉為 EAN-13
GTIN-14 14 I PPP MMMM IIIII C 箱購或物流單位
ISBN-13 13 978/979 + ... 書籍,格式上與 EAN-13 相同

位數說明(EAN-13)


2. 校驗碼演算法

EAN-13

輸入:前 12 位數字 d[0] 到 d[11]

加權求和:
  sum = d[0]*1 + d[1]*3 + d[2]*1 + d[3]*3 + ... + d[11]*3

校驗碼:
  check = (10 - sum % 10) % 10

驗證:check == d[12]
def validate_ean13(code: str) -> bool:
    """驗證 EAN-13 校驗碼。"""
    if len(code) != 13 or not code.isdigit():
        return False
    total = sum(int(d) * (1 if i % 2 == 0 else 3) for i, d in enumerate(code[:12]))
    check = (10 - total % 10) % 10
    return check == int(code[12])

EAN-8

輸入:前 7 位數字 d[0] 到 d[6]

加權求和:
  sum = d[0]*3 + d[1]*1 + d[2]*3 + d[3]*1 + d[4]*3 + d[5]*1 + d[6]*3

校驗碼:
  check = (10 - sum % 10) % 10

驗證:check == d[7]
def validate_ean8(code: str) -> bool:
    """驗證 EAN-8 校驗碼。"""
    if len(code) != 8 or not code.isdigit():
        return False
    total = sum(int(d) * (3 if i % 2 == 0 else 1) for i, d in enumerate(code[:7]))
    check = (10 - total % 10) % 10
    return check == int(code[7])

UPC-A

UPC-A 可視為前面補 0 的 EAN-13:

def validate_upc_a(code: str) -> bool:
    """驗證 UPC-A,轉為 EAN-13 後檢查。"""
    if len(code) != 12 or not code.isdigit():
        return False
    return validate_ean13("0" + code)

GTIN-14

def validate_gtin14(code: str) -> bool:
    """驗證 GTIN-14 校驗碼。"""
    if len(code) != 14 or not code.isdigit():
        return False
    weights = [3, 1] * 7
    total = sum(int(d) * w for d, w in zip(code[:13], weights))
    check = (10 - total % 10) % 10
    return check == int(code[13])

通用驗證函式

def validate_barcode(code: str) -> tuple[bool, str]:
    """回傳 (是否有效, 格式名稱)。"""
    if not code or not code.isdigit():
        return False, "invalid"

    if len(code) == 13:
        return validate_ean13(code), "EAN-13"
    if len(code) == 8:
        return validate_ean8(code), "EAN-8"
    if len(code) == 12:
        return validate_upc_a(code), "UPC-A"
    if len(code) == 14:
        return validate_gtin14(code), "GTIN-14"
    return False, "invalid"

3. prefix 判讀原則

格式合法不代表一定適合直接進 item master。

建議至少分成下列幾類:

4. 常見誤判模式

  1. 通路內部碼:格式合法,但只在特定零售通路內有意義。
  2. 書碼混入978/979 在保健、美妝、書店型通路特別容易混入。
  3. 組合包污染:同一 GTIN 被拿去標單品與組合包頁。
  4. 箱購污染:外箱或箱購頁把單品碼拿去沿用。
  5. 佔位碼:像 000000000000000000000 這類值可能通過長度與校驗邏輯,但不應保留。

5. 建議驗證流程

原始字串
  ↓
只保留數字
  ↓
檢查長度是否為 8 / 12 / 13 / 14
  ↓
驗證校驗碼
  ↓
檢查 prefix 風險
  ↓
檢查 佔位碼 與重複數字模式
  ↓
結合名稱、包裝層級、時間與來源做語義判斷

6. 大量驗證時至少要留下哪些欄位

7. 一句話收尾

條碼驗證至少要分成兩層:先驗格式,再驗語義。真正難的通常不是校驗碼,而是條碼是不是被用在對的商品語境裡。