如何檢查貨櫃號碼(集裝箱號碼)是否正確?除了從資料庫尋找是否有此櫃號外,也可以透過核對校驗碼的方式來檢查該櫃號是否正確。 本篇我們就來研究一下貨櫃號碼的編碼規則和其校驗碼(或稱檢查碼)的取得方法,另外再提供之前寫的取得校驗碼的這段程式。
- 貨櫃號碼(集裝箱號碼)的編碼規則
- 校驗碼(Value of check digit) 的計算方法
- 以程式語言C#來取得校驗碼
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. 貨櫃號碼(集裝箱號碼)的編碼規則 :
在 ISO 6346 的第3部分 (3. Identification system and its associated marks) 對貨櫃號碼的編碼有詳細說明:此識別系統(指貨櫃號碼/集裝箱號碼)共11碼,應由以下要素組成:
- 所有者代碼(3碼):
貨櫃所有人代碼由三碼(三個大寫字母)組成母,是唯一的並應與國際集裝箱局 (BIC - Bureau International des Conteneurs) 註冊。
- 設備類別(1碼);
設備類別由以下三個拉丁字母大寫字母之一組成,
U :代表所有貨運貨櫃
J :為可拆卸貨櫃相關設備
Z :用於拖車和板架
- 序號(6碼):
由 6 位數字組成,如不足6位則前面補0,由所有者或運營商自行配號。
- 校驗碼(1碼):
只有一個數字,此校驗碼用以驗證上面的所有者代碼、設備類別和序號是否正確。
2. 校驗碼(Value of check digit)的計算方法
如上可知,一個貨櫃號碼含校驗碼應該是11碼,校驗碼的確定是經由一定的計算程序取得。可以透過以下A.1到A.4的說明即可了解其計算方法:
- A.1 等效值(Numerical equivalents ) :˙
貨櫃號碼的1到10碼都將被附於一個值(Equivalent values),各碼的值如表A的A.1 Equivalent values 部分。
- A.2 加權因子(Weighting factor) :
貨櫃號碼的1到10的每一個位置也被附於一個加權值(Weighting Values),如表A的A.2 Weighting Values 部分。
- A.3 模數(Modulus):
模數就是一個數除以另一個數的餘數。在此為將各個字元的A.1和A.2相乘後加總再除以11的餘數。
- A.4 校驗碼(Value of check digit):
將A.3計算後取得的模數(餘數),其個位值(餘數為10時取0)就是我們要的校驗碼(Value of check digit)。
歸納以上說明如下表A:
表A
3. 以程式語言C#來取得校驗碼
private static string getCheckDigitForContainerNo(string ContainerNo, ref string errString)
{
string checkdigit = "";
try
{
//1. store ContainerNo to array
char[] ContainerChar = ContainerNo.ToCharArray();
int[] EquivalentValuePerChar = new int[10];
int[] WeightValue = new int[10];
//Assign Weight values
int value = 2;
for(int power=0; power<=9; power++)
WeightValue[power] = (int)Math.Pow(value, power);
//Assign Equivalent Values
for (int i = 0; i <= 9; i++)
{
switch (ContainerChar[i])
{
case 'A':
if (i < 4) EquivalentValuePerChar[i] = 10;
break;
case 'B':
if (i < 4) EquivalentValuePerChar[i] = 12;
break;
case 'C':
if (i < 4) EquivalentValuePerChar[i] = 13;
break;
case 'D':
if (i < 4) EquivalentValuePerChar[i] = 14;
break;
case 'E':
if (i < 4) EquivalentValuePerChar[i] = 15;
break;
case 'F':
if (i < 4) EquivalentValuePerChar[i] = 16;
break;
case 'G':
if (i < 4) EquivalentValuePerChar[i] = 17;
break;
case 'H':
if (i < 4) EquivalentValuePerChar[i] = 18;
break;
case 'I':
if (i < 4) EquivalentValuePerChar[i] = 19;
break;
case 'J':
if (i < 4) EquivalentValuePerChar[i] = 20;
break;
case 'K':
if (i < 4) EquivalentValuePerChar[i] = 21;
break;
case 'L':
if (i < 4) EquivalentValuePerChar[i] = 23;
break;
case 'M':
if (i < 4) EquivalentValuePerChar[i] = 24;
break;
case 'N':
if (i < 4) EquivalentValuePerChar[i] = 25;
break;
case 'O':
if (i < 4) EquivalentValuePerChar[i] = 26;
break;
case 'P':
if (i < 4) EquivalentValuePerChar[i] = 27;
break;
case 'Q':
if (i < 4) EquivalentValuePerChar[i] = 28;
break;
case 'R':
if (i < 4) EquivalentValuePerChar[i] = 29;
break;
case 'S':
if (i < 4) EquivalentValuePerChar[i] = 30;
break;
case 'T':
if (i < 4) EquivalentValuePerChar[i] = 31;
break;
case 'U':
if (i < 4) EquivalentValuePerChar[i] = 32;
break;
case 'V':
if (i < 4) EquivalentValuePerChar[i] = 34;
break;
case 'W':
if (i < 4) EquivalentValuePerChar[i] = 35;
break;
case 'X':
if (i < 4) EquivalentValuePerChar[i] = 36;
break;
case 'Y':
if (i < 4) EquivalentValuePerChar[i] = 37;
break;
case 'Z':
if (i < 4) EquivalentValuePerChar[i] = 38;
break;
default:
if (i >= 4 && i <= 9)
EquivalentValuePerChar[i] = int.Parse(ContainerChar[i].ToString());
break;
}
}
//3. Get Grand TTL
int GrdTTL = 0;
int RtvCheckDigitLength = 1;
for (int i = 0; i <= 9; i++)
GrdTTL = GrdTTL + EquivalentValuePerChar[i] * WeightValue[i];
//4. Get checkdigit
string Remainder = (GrdTTL % 11).ToString();
checkdigit = Remainder.ToString().Substring(Remainder.ToString().Length - RtvCheckDigitLength, RtvCheckDigitLength);
}
catch (Exception ex)
{
string err = ex.ToString();
errString = "The Check digit cannot be calculated because of wrong Container number...!";
}
if (checkdigit == "")
errString = "The Check digit cannot be calculated because of wrong Container number...!";
return checkdigit;
}