public IDNumberValidationResult Validate(string number)
        {
            var result = new IDNumberValidationResult(number);
            result.AdditionalData = new NRNumberAdditionalData();

            result.CleanProvidedValue = number.ToAlphaNumericOnly().TrimStart("BE").TrimStart("be").Trim();

            try
            {
                if (!string.IsNullOrEmpty(result.CleanProvidedValue))
                {
                    var nonAllowedCharacters = new Regex(@"[^0-9. -]");

                    var rrnumber = string.Copy(result.CleanProvidedValue);

                    if (nonAllowedCharacters.IsMatch(rrnumber))
                    {
                        result.IsValid = false;
                        result.ValidationErrors.Add("Number contains non-allowed character");
                    }
                    else
                    {
                        //LENGTH MUST BE 11 DIGITS
                        if (rrnumber.Length != 11)
                        {
                            result.IsValid = false;
                            result.ValidationErrors.Add("Length != 11");
                        }
                        else
                        {
                            var birthDateOK = false;
                            var counterOK = false;
                            var controlOK = false;

                            var unknownBirthDay = false;
                            var born2kOrLater = false;

                            var gender = "(unknown)";

                            //FIRST 6 DIGITS ARE BIRTHDATE IN FORMAT YYMMDD
                            var birthDatePart = rrnumber.Substring(0, 6);

                            //NEXT 3 ARE COUNTER
                            var counterPart = rrnumber.Substring(6, 3);

                            //LAST 2 ARE CONTROLNUMBER
                            var controlPart = rrnumber.Substring(9, 2);

                            /* 1. CONTROL NUMBER CHECKING */
                            /******************************/

                            //CALCULATE CONTROLNUMER (= MOD 97 OF FIRST 9 DIGITS)
                            var calculatedControl = 97 - (int) (long.Parse(birthDatePart + counterPart)%97);

                            if (calculatedControl != int.Parse(controlPart))
                            {
                                /* IF THE CALCULATED CONTROL PART IS DIFFERENT THAN THE ONE IN THE INPUTSTRING
                                    * ADD A "2" IN FRONT OF THE BIRTHDATEPART AND RECALCULATE. THIS WAS INTRODUCED TO
                                    * ALLOW BIRTHDATES OF YEAR 2000 AND LATER
                                */

                                calculatedControl = 97 - (int) (long.Parse("2" + birthDatePart + counterPart)%97);

                                if (calculatedControl != int.Parse(controlPart))
                                {
                                    /* THE CALCULATION STILL DOESN'T MATCH THE CONTROLNUMER, SO THIS IS AN INVALID
                                        * REGISTRY NUMBER
                                    */

                                    controlOK = false;
                                }
                                else
                                {
                                    born2kOrLater = true;
                                    controlOK = true;
                                }
                            }
                            else
                                controlOK = true;

                            /* 2. BIRTHDATE CHECKING */
                            /*************************/

                            var d = birthDatePart;
                            //BUILD THE BIRTHDATE TO CHECK
                            if (born2kOrLater)
                                d = "20" + d;
                            else
                                d = "19" + d;
                            //END BUILD

                            var format = "yyyyMMdd";
                            DateTime birthDate;

                            birthDateOK = DateTime.TryParseExact(d, format, CultureInfo.CurrentCulture,
                                DateTimeStyles.None,
                                out birthDate);

                            if (!birthDateOK)
                            {
                                //MONTH AND/OR DAY CAN BE 00 IF THESE ARE UNKNOWN. IF THIS IS THE CASE, FLAG THE BIRTHDATE AS VALID ANYWAY
                                if (birthDatePart.Substring(2, 2).Equals("00") ||
                                    birthDatePart.Substring(4, 2).Equals("00"))
                                {
                                    unknownBirthDay = true;
                                    birthDateOK = true;
                                }
                            }

                            /* 3. COUNTER CHECKING */
                            /***********************/

                            /* COUNTERPART MUST BE BETWEEN 001 AND 997
                                * EVEN FOR FEMALE
                                * ODD FOR MALE
                            */
                            var counter = int.Parse(counterPart);

                            if (counter < 1 || counter > 997)
                                counterOK = false;
                            else if (counter%2 == 0) //EVEN
                            {
                                counterOK = true;
                                gender = "F"; //FEMALE
                            }
                            else
                            {
                                counterOK = true;
                                gender = "M"; //MALE
                            }

                            /* 4. PROCESS RESULTS */
                            /**********************/

                            if (!birthDateOK)
                            {
                                result.IsValid = false;
                                result.ValidationErrors.Add("Birthdate part not valid");
                            }

                            if (!counterOK)
                            {
                                result.IsValid = false;
                                result.ValidationErrors.Add("Counter part not valid");
                            }

                            if (!controlOK)
                            {
                                result.IsValid = false;
                                result.ValidationErrors.Add("Controlnumber part not valid");
                            }

                            if (!unknownBirthDay && birthDateOK)
                                ((NRNumberAdditionalData)(result.AdditionalData)).BirthDate = birthDate;

                            if (gender == "F")
                                ((NRNumberAdditionalData)(result.AdditionalData)).Gender = GenderEnum.Female;
                            else if (gender == "M")
                                ((NRNumberAdditionalData)(result.AdditionalData)).Gender = GenderEnum.Male;
                        }
                    }

                    if (!result.IsValid.HasValue)
                    {
                        result.IsValid = true;
                        result.ValidatedValue = rrnumber;
                    }
                    else //result.IsValid == false
                    {
                        result.AdditionalData = null;
                    }
                }
                else
                    throw new Exception("Number is empty");
            }
            catch (Exception ex)
            {
                result.ValidationException = ex;

                result.IsValid = null;
                result.ValidatedValue = null;
                result.AdditionalData = null;

            }

            return result;
        }
        public IDNumberValidationResult Validate(string number)
        {
            var result = new IDNumberValidationResult(number);
            result.AdditionalData = new NationalIDAdditionalData();

            result.CleanProvidedValue = number.ToAlphaNumericOnly().TrimStart("ZA").TrimStart("za").Trim();

            try
            {
                if (!string.IsNullOrEmpty(result.CleanProvidedValue))
                {
                    var nonAllowedCharacters = new Regex(@"[^0-9. -]");

                    var idnumber = string.Copy(result.CleanProvidedValue);

                    if (nonAllowedCharacters.IsMatch(idnumber))
                    {
                        result.IsValid = false;
                        result.ValidationErrors.Add("Number contains non-allowed character");
                    }
                    else
                    {
                        //LENGTH MUST BE 11 DIGITS
                        if (idnumber.Length != 13)
                        {
                            result.IsValid = false;
                            result.ValidationErrors.Add("Length != 13");
                        }
                        else
                        {
                            var birthDateOK = false;
                            var counterOK = false;
                            var citizenshipOK = false;
                            var raceOK = false;
                            var controlOK = false;

                            DateTime birthDate = new DateTime();
                            var gender = "(unknown)";
                            int? citizenship;
                            int? race;

                            //FIRST 6 DIGITS ARE BIRTHDATE IN FORMAT YYMMDD
                            var birthDatePart = idnumber.Substring(0, 6);

                            //NEXT 4 ARE COUNTER
                            var counterPart = idnumber.Substring(6, 4);

                            //NEXT 1 IS CITIZENSHIP
                            var citizenshipPart = idnumber.Substring(10, 1);

                            //NEXT 1 IS RACE (prior to 1994)
                            var racePart = idnumber.Substring(11, 1);

                            //LAST 1 IS CONTROLNUMBER
                            var controlPart = idnumber.Substring(12, 1);

                            /* CONTROL NUMBER CHECKING */
                            /******************************/

                            /*
                             * The checksum digit is calculated using the Luhn algorithm:[3]

                                A = The sum of the digits in the ID number in the odd positions (Excluding Z)
                                B = The number formed by the concatenation of the digits in the ID number in the even positions
                                C = The sum of the digits in (2 * B)
                                D = A + C
                                Z = 10 - (D mod 10)
                             */

                            int A = 0;
                            string strB = "";
                            int B = 0;
                            string strBtimes2 = "";
                            int C = 0;
                            int D = 0;
                            int Z = 0;

                            for (int odd = 0; odd <= 10; odd = odd + 2)
                            {
                                A += (int) Char.GetNumericValue(result.CleanProvidedValue[odd]);
                            }

                            for (int even = 1; even <= 12; even = even + 2)
                            {
                                strB += result.CleanProvidedValue[even].ToString();
                            }

                            B = Int32.Parse(strB);
                            strBtimes2 = (B*2).ToString();

                            for (int i = 0; i < strBtimes2.Length; i++)
                            {
                                C += (int) Char.GetNumericValue(strBtimes2[i]);
                            }

                            D = A + C;

                            Z = 10 - (D%10);

                            if (Z == (Int32.Parse(controlPart)))
                                controlOK = true;

                            /* COUNTER CHECKING */
                            /***********************/

                            /* COUNTERPART MUST BE BETWEEN 0000 AND 9999
                                * 0000 to 4999 FOR FEMALE
                                * 5000 to 9999 ODD FOR MALE
                            */
                            var counter = int.Parse(counterPart);

                            if (counter < 5000)
                            {
                                counterOK = true;
                                gender = "F"; //FEMALE
                            }
                            else
                            {
                                counterOK = true;
                                gender = "M"; //MALE
                            }

                            /* CITIZENSHIP CHECKING */
                            /*************************/

                            citizenship = Int32.Parse(citizenshipPart);
                            citizenshipOK = true;

                            /* RACE CHECKING */
                            /*************************/

                            race = Int32.Parse(racePart);
                            raceOK = true;

                            /* BIRTHDATE CHECKING */
                            /*************************/

                            //remark: system below assumes provided national id numbers contain birthdates from today or earlier, and the cutoff limit is 100 years back

                            var d = birthDatePart;

                            int currentYear = DateTime.Now.Year;
                            string currentYearCentury = currentYear.ToString().Substring(0, 2);
                            d = currentYearCentury + d;

                            var format = "yyyyMMdd";

                            birthDateOK = DateTime.TryParseExact(d, format, CultureInfo.CurrentCulture,
                                DateTimeStyles.None,
                                out birthDate);

                            if (birthDate > DateTime.Now.Date)
                            {
                                birthDate = birthDate.AddYears(-100);
                            }

                            /* 4. PROCESS RESULTS */
                            /**********************/

                            if (!birthDateOK)
                            {
                                result.IsValid = false;
                                result.ValidationErrors.Add("Birthdate part not valid");
                            }

                            if (!counterOK)
                            {
                                result.IsValid = false;
                                result.ValidationErrors.Add("Counter part not valid");
                            }

                            if (!citizenshipOK)
                            {
                                result.IsValid = false;
                                result.ValidationErrors.Add("Citizenship part not valid");
                            }

                            if (!raceOK)
                            {
                                result.IsValid = false;
                                result.ValidationErrors.Add("Race part not valid");
                            }

                            if (!controlOK)
                            {
                                result.IsValid = false;
                                result.ValidationErrors.Add("Controlnumber part not valid");
                            }

                            if (birthDateOK)
                                ((NationalIDAdditionalData)(result.AdditionalData)).BirthDate = birthDate;

                            if (gender == "F")
                                ((NationalIDAdditionalData)(result.AdditionalData)).Gender = GenderEnum.Female;
                            else if (gender == "M")
                                ((NationalIDAdditionalData)(result.AdditionalData)).Gender = GenderEnum.Male;
                        }
                    }

                    if (!result.IsValid.HasValue)
                    {
                        result.IsValid = true;
                        result.ValidatedValue = idnumber;
                    }
                    else //result.IsValid == false
                    {
                        result.AdditionalData = null;
                    }
                }
                else
                    throw new Exception("Number is empty");
            }
            catch (Exception ex)
            {
                result.ValidationException = ex;

                result.IsValid = null;
                result.ValidatedValue = null;
                result.AdditionalData = null;

            }

            return result;
        }
        public IDNumberValidationResult Validate(string number)
        {
            var result = new IDNumberValidationResult(number);
            result.CleanProvidedValue = number.ToAlphaNumericOnly().TrimStart("BE").TrimStart("be").Trim();

            try
            {
                if (!string.IsNullOrEmpty(result.CleanProvidedValue))
                {
                    var cbenumber = string.Copy(result.CleanProvidedValue);

                    if (cbenumber.Length == 9) //possibly old VAT numbers consist of only 9 characters
                    {
                        cbenumber = "0" + cbenumber;
                    }

                    if (cbenumber.Length != 10)
                    {
                        result.IsValid = false;
                        result.ValidationErrors.Add("Length != 10");
                    }
                    else
                    {
                        var numberBody = cbenumber.Substring(0, 8);
                        var controlNumber = cbenumber.Substring(8, 2);

                        if (numberBody[0].Equals('9')) //must start by 0 - 8
                        {
                            result.IsValid = false;
                            result.ValidationErrors.Add("Number must start by 0 - 8");
                        }
                        else
                        {
                            //CALCULATE CONTROLNUMER (= MOD 97 OF FIRST 9 DIGITS)
                            var calculatedControl = 97 - (int)(long.Parse(numberBody) % 97);

                            if (calculatedControl != int.Parse(controlNumber))
                            {
                                result.IsValid = false;
                                result.ValidationErrors.Add("Controlnumber part not valid");
                            }
                        }
                    }

                    if (!result.IsValid.HasValue)
                    {
                        result.IsValid = true;
                        result.ValidatedValue = cbenumber;
                    }
                }
                else
                    throw new Exception("Number is empty");
            }
            catch (Exception ex)
            {
                result.ValidationException = ex;

                result.IsValid = null;
                result.ValidatedValue = null;
                result.AdditionalData = null;
            }

            return result;
        }