如何檢查貨櫃號碼(集裝箱號碼)是否正確?

如何檢查貨櫃號碼(集裝箱號碼)是否正確?ISO 6346 編碼規則與校驗碼計算教學

如何檢查貨櫃號碼(集裝箱號碼)是否正確?ISO 6346 編碼規則與校驗碼計算教學

物流資訊系統 C# 程式開發 ISO 6346 規範

在海運與物流系統中,確認貨櫃號碼(Container No.)的正確性非常關鍵。除了直接從資料庫檢索外,最有效率的初步驗證方式就是核對校驗碼(Check Digit)

本文將詳細解析 ISO 6346 貨櫃編碼規則、校驗碼的數學計算邏輯,並提供完整實用的 C# 範例程式碼

ISO 6346 貨櫃編號結構示意圖
▲ 圖解 ISO 6346 貨櫃編號結構拆解圖 (以櫃號 TCNU426045[0] 為例)

1. 貨櫃號碼(集裝箱號碼)的編碼規則

根據 ISO 6346 國際標準第 3 部分(Identification system and its associated marks),一個標準貨櫃識別碼由 11 碼 組成,結構如下:

第 1 ~ 3 碼
所有者代碼 (Owner Code)

由 3 個大寫英文字母組成,必須向國際集裝箱局 (BIC, Bureau International des Conteneurs) 註冊,確保全球唯一。

第 4 碼
設備類別 (Equipment Category)

由 1 個拉丁大寫字母組成:

  • U:所有貨運貨櫃 (Freight container)
  • J:可拆卸貨櫃相關設備 (Attachable equipment)
  • Z:拖車和板架 (Trailers and chassis)
第 5 ~ 10 碼
序號 (Serial Number)

由 6 位數字組成。若不足 6 位則前方補 0,由所有者或營運商自行配號。

第 11 碼
校驗碼 (Check Digit)

僅 1 位數字,用於驗證前 10 碼(所有者代碼、設備類別、序號)在輸入或傳輸過程中的正確性。

2. 校驗碼(Check Digit)的計算方法

校驗碼的計算採用「加權模數 11 演算法」,步驟說明如下:

  • A.1 字母對應等效值 (Numerical Equivalents)
    將前 10 碼字元轉換為對應數值。數字保持原值(0~9),英文字母(A~Z)則跳過 11 的倍數(如 11, 22, 33)後依序賦予 10 至 38 的數值。
  • A.2 加權因子 (Weighting Factor)
    1 到 10 的每個位置都有固定的加權值,分別為 2 的 0 次方到 9 次方(即 20, 21, 22 ... 29):
    [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
  • A.3 模數計算 (Modulus 11)
    將每一個字元的「等效值 (A.1)」與對應位置的「加權因子 (A.2)」相乘後全部加總,再將總和除以 11 取餘數:
    餘數 = ( ∑ (等效值 × 加權因子) ) % 11
  • A.4 確定校驗碼 (Value of Check Digit)
    計算出的餘數即為校驗碼。特別注意:若餘數為 10,則校驗碼取為 0

字母對應等效值表 (A.1 Numerical Equivalents Table)

字母對應值 字母對應值 字母對應值
A10J20S30
B12K21T31
C13L23U32
D14M24V34
E15N25W35
F16O26X36
G17P27Y37
H18Q28Z38
I19R29--

3. 實例計算演練

以貨櫃號碼 TCNU4260450 為例,驗證其第 11 碼校驗碼是否為 0

位置 Index 12345678910 總和 Sum
貨櫃字元 TCNU426045 -
A.1 等效值 31132532426045 -
A.2 加權因子 1248163264128256512 -
乘積 (A.1 × A.2) 31261002566464384010242560 4509

計算結果:

1. 總和加總 = 4509

2. 除以 11 取餘數: 4509 % 11 = 0

3. 取得校驗碼為 0,與貨櫃號碼第 11 碼完全符合!

4. 以程式語言 C# 來取得校驗碼

以下提供經過優化與重構的 C# 函式,能高效且精準地計算出 ISO 6346 貨櫃校驗碼:

ContainerCheckDigit.cs C#
using System;
using System.Collections.Generic;

public class ContainerValidator
{
    /// <summary>
    /// 計算並取得貨櫃號碼的校驗碼 (Check Digit)
    /// </summary>
    /// <param name="containerNo">前 10 碼或完整 11 碼的貨櫃號碼</param>
    /// <returns>算出的校驗碼字串,失敗則傳回 null</returns>
    public static string GetCheckDigit(string containerNo)
    {
        if (string.IsNullOrWhiteSpace(containerNo) || containerNo.Length < 10)
            return null;

        containerNo = containerNo.ToUpper().Trim();

        // A.1 字元對應等效值對照表
        Dictionary<char, int> charValues = new Dictionary<char, int>()
        {
            {'A', 10}, {'B', 12}, {'C', 13}, {'D', 14}, {'E', 15},
            {'F', 16}, {'G', 17}, {'H', 18}, {'I', 19}, {'J', 20},
            {'K', 21}, {'L', 23}, {'M', 24}, {'N', 25}, {'O', 26},
            {'P', 27}, {'Q', 28}, {'R', 29}, {'S', 30}, {'T', 31},
            {'U', 32}, {'V', 34}, {'W', 35}, {'X', 36}, {'Y', 37},
            {'Z', 38}
        };

        int totalSum = 0;

        // 計算前 10 碼的加權總和
        for (int i = 0; i < 10; i++)
        {
            char c = containerNo[i];
            int equivalentValue;

            if (char.IsLetter(c))
            {
                if (!charValues.TryGetValue(c, out equivalentValue))
                    return null; // 無效英文字元
            }
            else if (char.IsDigit(c))
            {
                equivalentValue = c - '0';
            }
            else
            {
                return null; // 特殊符號無效
            }

            // 加權因子為 2^i
            int weight = (int)Math.Pow(2, i);
            totalSum += equivalentValue * weight;
        }

        // A.3 取 11 模數餘數
        int remainder = totalSum % 11;

        // A.4 餘數為 10 時轉為 0
        int checkDigit = (remainder == 10) ? 0 : remainder;

        return checkDigit.ToString();
    }
}

沒有留言:

張貼留言

>