Search This Blog

Title of the confirm dialog

Description of what is about to happen

Luhn Algorithm


Known as the "modulus 10" or "mod 10" algorithm, is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers, IMEI numbers, National Provider Identifier numbers in the US, and Canadian Social Insurance
Numbers. It was created by IBM scientist Hans Peter Luhn and described in U.S. Patent No. 2,950,048, filed on January 6, 1954, and granted on August 23, 1960.

(ref https://en.wikipedia.org/wiki/Luhn_algorithm)


Source Code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105 
106
107
108 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; // .Net Framework 4.0


namespace TechScales
{
    internal static class Luhn
    {
        /// <summary>
        /// Luhn Algoritm.
        /// </summary>
        /// <param name="numbers">numbers to check</param> 
        internal static bool IsValid(string numbers)
        {
            int len = numbers.Length;
            int dgt = 0, sum = 0;
            int pos = 0; //the current process number (to calc odd/even proc)
            for (int i = len - 1; i >= 0; i--)
            {
                //digit on right most
                string rgt = numbers.Substring(i, 1);
                //parse 
                if (!int.TryParse(rgt, out dgt)) { return false; }
                //double value of every 2nd right most
                //if value = 2digits, sum the digits by substract by 9
                if (pos % 2 != 0) { if ((dgt *= 2) > 9) { dgt -= 9; } }
                //increase the proc number
                pos++;
                //summarize the processed digits
                sum += dgt;
            }
            //if sum is divisible by 10, return valid, else notValid
            return (sum % 10 == 0);
        }

        /// <summary>
        /// Luhn Algoritm.
        /// </summary>
        /// <param name="sidNum">numbers to check</param> 
        internal static bool IsValidA(string numbers)
        {
            int sum = 0, pos = 0;
            // select numeric only
            // reverse collection, need to sumarize from right most
            var num = numbers.Where(c => "0123456789".Contains(c)).Reverse();
            foreach(var n in num)
            {
                // multiply by 2 of every even digit value.
                // if digit value > 9, substract it by 9.
                // perform addition  
                var i = n - 48;
                sum += pos % 2 != 0 ? ((i *= 2) > 9 ? (i - 9) : i) : i;
                // next digit
                pos++;
            };
            return sum % 10 == 0;
        }

        /// <summary>
        /// extension: verify string by Luhn algorithm
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        internal static bool IsLuhnVerified(this string arg)
        {
            return !string.IsNullOrWhiteSpace(arg) ? IsValidA(arg) : false;
        }

        /// <summary>
        /// extension: verify numbers by Luhn algorithm
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        internal static bool IsLuhnVerified(this long arg)
        {
            return
                !string.IsNullOrWhiteSpace(arg.ToString()) ?
                IsValidA(arg.ToString()) : false;
        }

        /// <summary>
        /// get valid check digit of complete string numbers
        /// using Luhn algorithm<para></para>
        /// string cannot be empty/null value
        /// </summary>
        /// <param name="arg"></param>
        /// <param name="numOnly">get number only</param>
        /// <returns></returns>
        internal static int ValidCheckDigit(string arg, bool numOnly = false)
        {
            int sum = 0, pos = 0;
            var num = (!numOnly ? 
                      arg : 
                      arg.Where(c => "0123456789".Contains(c)))
                      .Reverse();
            foreach (var n in num)
            {
                var i = n - 48;
                sum += pos % 2 == 0 ? ((i *= 2) > 9 ? (i - 9) : i) : i;
                pos++;
            }
            return ((int)Math.Ceiling(sum / 10d) * 10) - sum;
        }
    }
}


Test

Immediate Window
?Luhn.IsValidA("4987 6532 1012 3456")
 true
?NPWP.ValidCheckCode("12345678")
 2

var yes = Luhn.IsValidA("4987 6532 1012 3456"); // return true var dgt = Luhn.ValidCheckDigit("4987 6532 1012 345"); // return 6


TOP

Shipping Container Code Validation

Derivated from ISO 6346

ISO 6346 is an international standard covering the coding, identification and marking of intermodal (shipping) containers used within containerized intermodal freight transport. The standard establishes a visual identification system for every container
that includes a unique serial number (with check digit), the owner, a country code, a size, type and equipment category as well as any operational marks. The standard is managed by the International Container Bureau (BIC).
(ref https:s://en.wikipedia.org/wiki/ISO_6346)


Container Code Format ISO6346

Format AAAX0000009
AAA Owner Code
The owner code consists of three capital letters of the Latin alphabet to indicate the owner or principal operator of the container. Such code needs to be registered at the Bureau International des Conteneurs in Paris to ensure uniqueness worldwide.
X Equipment Category Identifier
The equipment category identifier consists of one of the following capital letters of the Latin alphabet:
J : detachable freight container-related equipment
U : freight containers
Z : trailers and chassis
Under the ISO code, then, only J, U and Z are in use—the reefer container is identified by means of the size type code.
000000
Serial Number
The serial number consists of 6 numeric digits, assigned by the owner or operator, uniquely identifying the container within that owner/operator's fleet.
9
Check Digit
The check digit consists of one numeric digit providing a means of validating the recording and transmission accuracies of the owner code and serial number.


Source Code


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107 
108 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; // .Net Framework 4.0


namespace TechScales
{
    internal static class ContainerCodeValidation
    {
        /// <summary>
        /// check alphanumeric container code, 
        /// code4: 
        /// J = EQUIPMENTS &amp; TOOLS,
        /// U = Universal,
        /// Z = CHASSIS &amp; TRAILER
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        public static string GetCheckDigitContainerID(this string arg)
        {
            if (string.IsNullOrWhiteSpace(arg))
                return string.Concat(arg, "☺");
            // remove space, make uppercase
            var id = arg.Trim().Replace(" ", string.Empty).ToUpper();
            // make 10 chars or take 10 chars
            id = id.Length < 10 ? 
                 id.PadRight(10, '0') : 
                 (id.Length > 10 ? id.Substring(0, 10) : id);
            // alphabet, numeric and space only
            foreach (var s in id)
            {
                 if (!"ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789".Contains(s)) 
                     return arg; 
            }
            // valid code position 4th
            var code4 = "JUZ";
            for (var c = 0; c < "AAAX".Length; c++)
            {
                if (c < 3 && 
                    !"ABCDEFGHIJKLMNOPQRSTUVWXYZ".Contains(id[c]))
                    return arg;
                if (c == 3 && !code4.Contains(id[c])) return arg; 
            }
            for (var c = 0; c < 10; c++) 
            { if (!"0123456789".Contains(id[c]))  return arg; }
            int numer = 0, azFrom = 10, azTo = 39;
            var codAZ = Enumerable.Range(azFrom, (azTo - azFrom))
                        .Where(n => n % 11 > 0 && n <= azTo)
                        .ToArray();
            var multi = new int[] { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 };
            var codes = new List<int>();
            try
            {
                var i = 0;
                foreach (var s in id)
                {
                    numer = 0; 
                    if (i < 4) { numer = codAZ[(int)s - 65]; } 
                    else { int.TryParse(s.ToString(), out numer); }
                    numer *= multi[i]; codes.Add(numer);
                    i++;
                }
                numer = codes.Sum();
                numer -= (int)Math.Floor(numer / 11d) * 11;
                id = string.Concat(id, " ", numer);
            }
            catch { id = string.Concat(id, "-1"); }
            codAZ = null; multi = null; codes.Clear(); codes = null;
            return id;
        }
        /// <summary>
        /// extension: containe code validation
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        public static bool IsValidContainerCode(this string arg)
        {
            var ret = ""; return IsValidContainerCode(arg, ref ret);
        }
        /// <summary>
        /// extension: containe code validation
        /// </summary>
        /// <param name="arg"></param>
        /// <param name="result">filtered string</param>
        /// <returns></returns>
        public static bool IsValidContainerCode(
               this string arg, ref string result)
        {
            var valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            // check valid string, check string length must be 11 
            var v0 = string.Join(string.Empty, 
                     // make uppercase
                     arg.ToUpper()
                     // remove empty char
                     .Replace(" ", string.Empty)
                     // alphabet and numeric only
                     .Where(f => valid.Contains(f))
                     // as array for string.join purpose
                     .ToArray()); if (v0.Length != 11) { return false; }
            // do checking methode, get result
            var v1 = v0.GetCheckDigitContainerID().Replace(" ", ""); 
            result = v0;
            return v0 == v1;
        }
    }
}


Test

Immediate Window
?"CSQU3054383".IsValidContainerCode()
 true

bool yes = "CSQU3054383".IsValidContainerCode(); // return true

TOP   ISO6346 Live Validation