示例#1
0
            /// <summary>
            /// ToValidValue - enforce max and min value of a nullable boolean
            /// SOURCE: https://stackoverflow.com/questions/3115678/converting-string-to-int-using-c-sharp
            /// </summary>
            /// <param name="boolToClean"></param>
            /// <returns></returns>
            public bool?ToValidValue(string boolToClean)
            {
                bool?tmpResult = false;

                try
                {
                    if (String.IsNullOrWhiteSpace(boolToClean))
                    {
                        tmpResult = null; //Always return null. Protects against a gigabyte of whitespace!!!
                    }
                    else
                    {
                        bool value;

                        string truncatedValue = SaniCore.Truncate.ToValidLength(boolToClean, 5);
                        bool   isSuccess      = bool.TryParse(truncatedValue, out value);

                        if (isSuccess)
                        {
                            tmpResult = value;
                        }
                        else
                        {
                            throw new Exception("Parse Failure.");
                        }
                    }
                }
                catch (Exception ex)
                {
                    SaniExceptionHandler.TrackOrThrowException(TruncateLength, SaniType, SaniCore, "MinMax: ", "Error boolean to valid MinMax value: ", boolToClean, ex);
                }
                return(tmpResult);
            }
示例#2
0
        /// <summary>
        /// TruncateToValidLength -  max length of a string
        /// </summary>
        /// <param name="strToClean"></param>
        /// <returns></returns>
        public string ToValidLength(string strToClean, int strMaxLength)
        {
            string tmpResult = String.Empty;

            try
            {
                if (string.IsNullOrWhiteSpace(strToClean))
                {
                    tmpResult = null; //Always return null. Protects against a gigabyte of whitespace!!!
                }
                else
                {
                    if (strToClean.Length >= strMaxLength)
                    {
                        tmpResult = strToClean.Substring(0, strMaxLength);
                    }
                    else
                    {
                        tmpResult = strToClean;
                    }
                }
            }
            catch (Exception ex)
            {
                SaniExceptionHandler.TrackOrThrowException(TruncateLength, SaniType, SaniCore, "Truncate: ", "Error truncating to valid length: ", strToClean, ex);
            }
            return(tmpResult);
        }
示例#3
0
        /// <summary>
        /// Normalize Unicode for if you are planning to compare against a Unicode AllowedList (so you know which Normalization Form to use.)
        /// </summary>
        /// <param name="strToClean"></param>
        /// <returns></returns>
        public string NormalizeUnicode(string strToClean)
        {
            string tmpResult = String.Empty;

            try
            {
                //SOURCE: https://stackoverflow.com/questions/15683717/unicode-to-ascii-conversion-mapping

                if (string.IsNullOrWhiteSpace(strToClean))
                {
                    tmpResult = null; //Always return null. Protects against a gigabyte of whitespace!!!
                }
                else
                {
                    tmpResult = strToClean.Normalize(NormalizationForm.FormKC);

                    //This will retain diacritic characters after normalization.
                    tmpResult = new string(tmpResult.Where(c =>
                    {
                        UnicodeCategory category = CharUnicodeInfo.GetUnicodeCategory(c);
                        return(category != UnicodeCategory.NonSpacingMark);
                    }).ToArray());
                }
            }
            catch (Exception ex)
            {
                SaniExceptionHandler.TrackOrThrowException(TruncateLength, SaniType, SaniCore, "NormalizeOrLimit: ", "Error normalizing unicode: ", strToClean, ex);
            }

            return(tmpResult);
        }
示例#4
0
        /// <summary>
        /// Limit a Unicode string to just the limited subset of ASCII-compatible numbers, aka Latin numbers.
        /// </summary>
        /// <param name="strToClean"></param>
        /// <returns></returns>
        public string ToASCIINumbersOnly(string strToClean, bool allowSpaces, bool allowParens, bool allowNegativeSign, bool allowCommaAndDot)
        {
            string tmpResult = String.Empty;

            try
            {
                if (string.IsNullOrWhiteSpace(strToClean))
                {
                    tmpResult = null; //Always return null. Protects against a gigabyte of whitespace!!!
                }
                else
                {
                    tmpResult = ToASCIIOnly(strToClean);

                    //limit further
                    tmpResult = (new string(tmpResult.ToCharArray().Where(c => ((48 <= (int)c && (int)c <= 57) ||
                                                                                (allowSpaces?((int)c == 32):false) || //32 = space
                                                                                (allowParens ? (((int)c == 40) || ((int)c == 41)) : false) ||//40 and 41 = parens
                                                                                (allowCommaAndDot ? ((int)c == 44) : false) || //44 = ,
                                                                                (allowNegativeSign ? ((int)c == 45) : false) || //45 = dash
                                                                                (allowCommaAndDot ? ((int)c == 46) : false) //46 = dot

                                                                                )).ToArray()));
                }
            }
            catch (Exception ex)
            {
                SaniExceptionHandler.TrackOrThrowException(TruncateLength, SaniType, SaniCore, "NormalizeOrLimit: ", "Error limiting unicode to ASCII Numbers Only: ", strToClean, ex);
            }
            return(tmpResult);
        }
示例#5
0
            /// <summary>
            /// MatchesRegex - case-sensitive, single-line Regex match against string to check using regexToMatch expression after truncating stringToCheck and limiting to ASCII. If it matches, stringToCheck ref will be set to the truncated value and limited to ASCII.
            /// </summary>
            /// <param name="stringToCheck"></param>
            /// <returns></returns>
            public bool?MatchesRegex(ref string stringToCheck, string regexToMatch, int lengthToTruncateTo)
            {
                bool?tmpResult = false;

                try
                {
                    if (String.IsNullOrWhiteSpace(regexToMatch))
                    {
                        throw new Exception("AllowedRegex cannot be null or empty!");
                    }

                    if (String.IsNullOrWhiteSpace(stringToCheck))
                    {
                        tmpResult = null; //Always return null. Protects against a gigabyte of whitespace!!!
                    }
                    else
                    {
                        //Truncate first to lean towards more conservative. Have to pass in string in FormKC format.
                        string truncatedValue = SaniCore.Truncate.ToValidLength(stringToCheck, lengthToTruncateTo);
                        string limitedToASCII = SaniCore.NormalizeOrLimit.ToASCIIOnly(truncatedValue);

                        //This regex will ALLOW valid expressions based on a matching Regex.
                        string regex2 = regexToMatch;

                        bool matchOnWindows = false;
                        if (SaniCore.CompileRegex)
                        {
                            //May cause build to be slower but runtime Regex to be faster . . . let developer choose.
                            matchOnWindows = Regex.IsMatch(limitedToASCII, regex2, RegexOptions.Singleline | RegexOptions.Compiled);
                        }
                        else
                        {
                            matchOnWindows = Regex.IsMatch(limitedToASCII, regex2, RegexOptions.Singleline);
                        }

                        if (matchOnWindows)
                        {
                            stringToCheck = limitedToASCII;
                            tmpResult     = true;
                        }
                        else
                        {
                            throw new Exception("StringToCheck does NOT match Allowed Regex.");
                        }
                    }
                }
                catch (Exception ex)
                {
                    SaniExceptionHandler.TrackOrThrowException(TruncateLength, SaniType, SaniCore, "AllowedList: ", "Issue with AllowedList Matches Regex method", stringToCheck, ex);
                }
                return(tmpResult);
            }
示例#6
0
            /// <summary>
            /// ToValidValue - enforce max and min value of a nullable long (SQL Server BigInt)
            /// SOURCE: https://stackoverflow.com/questions/3115678/converting-string-to-int-using-c-sharp
            /// </summary>
            /// <param name="longToClean"></param>
            /// <returns></returns>
            public long?ToValidValue(string longToClean, long longMaxValue, long longMinValue)
            {
                long?tmpResult = 0;

                try
                {
                    if (String.IsNullOrWhiteSpace(longToClean))
                    {
                        tmpResult = null; //Always return null. Protects against a gigabyte of whitespace!!!
                    }
                    else
                    {
                        long value;

                        if (Math.Min(longMaxValue, longMinValue) == longMaxValue)
                        {
                            throw new Exception("Invalid parameters: minimum value cannot be greater than the maximum value.");
                        }

                        bool isSuccess = long.TryParse(longToClean, out value);
                        if (isSuccess)
                        {
                            if (Math.Min(value, longMinValue) == value)
                            {
                                tmpResult = longMinValue;//if min value has to be applied then apply it.
                            }
                            else //otherwise check whether the max value needs to be applied.
                            {
                                if (Math.Max(value, longMaxValue) == value)
                                {
                                    tmpResult = longMaxValue;
                                }
                                else
                                {
                                    tmpResult = value;
                                }
                            }
                        }
                        else
                        {
                            throw new Exception("Parse Failure.");
                        }
                    }
                }
                catch (Exception ex)
                {
                    SaniExceptionHandler.TrackOrThrowException(TruncateLength, SaniType, SaniCore, "MinMax: ", "Error long to valid MinMax value: ", longToClean, ex);
                }
                return(tmpResult);
            }
示例#7
0
            /// <summary>
            /// EqualsValueIgnoreCase - compare string to check against allowedList value while ignoring case sensitivity. Sets stringToCheck to allowedList value (including case) if equivalent.
            /// </summary>
            /// <param name="stringToCheck"></param>
            /// <returns></returns>
            public bool?EqualsValueIgnoreCase(ref string stringToCheck, string allowedListValue, int lengthToTruncateTo)
            {
                bool?tmpResult = false;

                try
                {
                    if (String.IsNullOrWhiteSpace(allowedListValue))
                    {
                        throw new Exception("AllowedList value cannot be null or empty!");
                    }

                    if (String.IsNullOrWhiteSpace(stringToCheck))
                    {
                        tmpResult = null; //Always return null. Protects against a gigabyte of whitespace!!!
                    }
                    else
                    {
                        StringComparison ic = StringComparison.OrdinalIgnoreCase;

                        //Truncate first to lean towards more conservative. Have to pass in string in FormKC format.
                        string truncatedValue    = SaniCore.Truncate.ToValidLength(stringToCheck, lengthToTruncateTo);
                        string normalizedUnicode = SaniCore.NormalizeOrLimit.NormalizeUnicode(truncatedValue);

                        bool isSuccess = (normalizedUnicode.Equals(allowedListValue, ic));

                        if (isSuccess)
                        {
                            stringToCheck = allowedListValue;
                            tmpResult     = true;
                        }
                        else
                        {
                            throw new Exception("StringToCheck does NOT equal allowedList value.");
                        }
                    }
                }
                catch (Exception ex)
                {
                    SaniExceptionHandler.TrackOrThrowException(TruncateLength, SaniType, SaniCore, "AllowedList: ", "Issue with AllowedList Unicode EqualsIgnoreCase method", stringToCheck, ex);
                }
                return(tmpResult);
            }
示例#8
0
            /// <summary>
            /// EndsWithSuffixIgnoreCase - compare string to check against allowedList value at the end of the string ignoring case.
            /// </summary>
            /// <param name="stringToCheck"></param>
            /// <returns></returns>
            public bool?EndsWithSuffixIgnoreCase(ref string stringToCheck, string allowedListSuffix, int lengthToTruncateTo)
            {
                bool?tmpResult = false;

                try
                {
                    if (String.IsNullOrWhiteSpace(allowedListSuffix))
                    {
                        throw new Exception("AllowedList Suffix cannot be null or empty!");
                    }

                    if (String.IsNullOrWhiteSpace(stringToCheck))
                    {
                        tmpResult = null; //Always return null. Protects against a gigabyte of whitespace!!!
                    }
                    else
                    {
                        StringComparison ic = StringComparison.OrdinalIgnoreCase;

                        //Truncate first to lean towards more conservative. Have to pass in string in FormKC format.
                        string truncatedValue = SaniCore.Truncate.ToValidLength(stringToCheck, lengthToTruncateTo);
                        string limitedToASCII = SaniCore.NormalizeOrLimit.ToASCIIOnly(truncatedValue);

                        bool isSuccess = (limitedToASCII.EndsWith(allowedListSuffix, ic));

                        if (isSuccess)
                        {
                            stringToCheck = limitedToASCII;
                            tmpResult     = true;
                        }
                        else
                        {
                            throw new Exception("StringToCheck does NOT start with the allowedList Suffix while ignoring case.");
                        }
                    }
                }
                catch (Exception ex)
                {
                    SaniExceptionHandler.TrackOrThrowException(TruncateLength, SaniType, SaniCore, "AllowedList: ", "Issue with AllowedList ASCII EndsWithSuffixIgnoreCase method", stringToCheck, ex);
                }
                return(tmpResult);
            }
            /// <summary>
            /// Review - compare string to check against restrictedList value while ignoring case. Returns true if any issue or restrictedList match found. Ref stringToCheck will be cleansed.
            /// </summary>
            /// <param name="stringToCheck"></param>
            /// <returns></returns>
            public bool?ReviewIgnoreCase(ref string stringToCheck, List <string> restrictedListValues, int lengthToTruncateTo, bool checkForHexChars = true, bool checkForCommonMaliciousChars = true)
            {
                bool?            tmpResult = false;
                StringComparison ic        = StringComparison.InvariantCultureIgnoreCase;//be more inclusive for restrictedList
                bool             hasCommonMaliciousChars = false;
                bool             hasOtherMaliciousChars  = false;

                try
                {
                    if (restrictedListValues == null || restrictedListValues.Count == 0)
                    {
                        tmpResult = true;
                        throw new Exception("RestrictedList value cannot be null or empty list!");
                    }

                    if (String.IsNullOrWhiteSpace(stringToCheck))
                    {
                        tmpResult = null; //Always return null. Protects against a gigabyte of whitespace!!!
                    }
                    else
                    {
                        if (checkForCommonMaliciousChars == true)
                        {
                            //Review in Unicode instead of ASCII for this case since the common malicious characters are listed mostly in unicode chars

                            string truncatedString  = SaniCore.Truncate.ToValidLength(stringToCheck, lengthToTruncateTo);
                            string normalizedString = SaniCore.NormalizeOrLimit.NormalizeUnicode(truncatedString);

                            int    initialLengthStr   = normalizedString.Length;
                            string strPostReplacement = String.Empty;

                            bool firstPass = true;

                            foreach (string badVal in GenerateCommonRestrictedList())
                            {
                                if (firstPass == true)
                                {
                                    strPostReplacement = Replace(normalizedString, badVal, string.Empty, ic);
                                    firstPass          = false;
                                }
                                else
                                {
                                    strPostReplacement = Replace(strPostReplacement, badVal, string.Empty, ic);
                                }

                                if (strPostReplacement.Length < initialLengthStr) //new length will be shorter since restrictedList chars replaced
                                {
                                    hasCommonMaliciousChars = true;
                                }
                            }

                            if (hasCommonMaliciousChars)
                            {
                                tmpResult     = true;
                                stringToCheck = strPostReplacement;

                                //FIRE THIS LATER: throw new Exception("StringToCheck contains a common malicious character.");
                            }
                            else
                            {
                                tmpResult = false;
                            }
                        }

                        if (checkForHexChars == true)
                        {
                            List <string> hexRestrictedList = RestrictedList.GenerateHexAndEscapeSeqRestrictedList();

                            //Check for hex values first before the developer - defined restrictedList to avoid tainting
                            hexRestrictedList.AddRange(restrictedListValues); //Add restricted values to the end
                            restrictedListValues = hexRestrictedList;
                        }

                        string truncatedValue = SaniCore.Truncate.ToValidLength(stringToCheck, lengthToTruncateTo);
                        string limitedToASCII = SaniCore.NormalizeOrLimit.ToASCIIOnly(truncatedValue);

                        int    initialLength         = limitedToASCII.Length;
                        string stringPostReplacement = String.Empty;

                        bool firstPassAgain = true;
                        foreach (string badVal in restrictedListValues)
                        {
                            if (firstPassAgain == true)
                            {
                                stringPostReplacement = Replace(limitedToASCII, badVal, string.Empty, ic);
                                firstPassAgain        = false;
                            }
                            else
                            {
                                stringPostReplacement = Replace(stringPostReplacement, badVal, string.Empty, ic);
                            }

                            if (stringPostReplacement.Length < initialLength) //new length will be shorter since restrictedList chars replaced
                            {
                                hasOtherMaliciousChars = true;
                            }
                        }

                        if (hasOtherMaliciousChars)
                        {
                            tmpResult = true;

                            stringToCheck = stringPostReplacement;

                            if (hasCommonMaliciousChars)
                            {
                                throw new Exception("StringToCheck contains a common malicious character and a restrictedList value.");
                            }
                            else
                            {
                                throw new Exception("StringToCheck contains a restrictedList value.");
                            }
                        }
                        else
                        {
                            if (hasCommonMaliciousChars)
                            {
                                throw new Exception("StringToCheck contains a common malicious character.");
                            }

                            //if once tmpResult has been set to true, do NOT un-set tmpResult to false
                        }
                    }
                }
                catch (Exception ex)
                {
                    tmpResult = true;
                    SaniExceptionHandler.TrackOrThrowException(TruncateLength, SaniType, SaniCore, "RestrictedList: ", "Issue with RestrictedList ReviewIgnoreCase method", stringToCheck, ex);
                }
                return(tmpResult);
            }
示例#10
0
            /// <summary>
            /// ToValidValue - enforce max and min value of a nullable datetime
            /// SOURCE: https://stackoverflow.com/questions/3115678/converting-string-to-int-using-c-sharp
            /// </summary>
            /// <param name="dateToClean"></param>
            /// <returns></returns>
            public DateTime?ToValidValue(string dateToClean, DateTime dateMaxValue, DateTime dateMinValue, DateUtil.DataType dateDataType, DateUtil.Delim dateDelimiter, DateFormat dateFormat, bool expectTrailingAMorPM)
            {
                String[] strFormat = null;
                DateTime?tmpResult = null;

                try
                {
                    if (String.IsNullOrWhiteSpace(dateToClean))
                    {
                        tmpResult = null; //Always return null. Protects against a gigabyte of whitespace!!!
                    }
                    else
                    {
                        DateTime value;

                        if (DateTime.Compare(dateMinValue.ToUniversalTime(), dateMaxValue.ToUniversalTime()) > 0)
                        {
                            throw new Exception("Invalid parameters: minimum date cannot be greater than the maximum date.");
                        }

                        if (dateDelimiter == DateUtil.Delim.ForwardSlash)
                        {
                            if (dateToClean.IndexOf(@"/") == -1)
                            {
                                throw new Exception("Invalid date: missing forward slash delimiter.");
                            }
                        }
                        if (dateDelimiter == DateUtil.Delim.Dash)
                        {
                            if (dateToClean.IndexOf(@"-") == -1)
                            {
                                throw new Exception("Invalid date: missing dash delimiter.");
                            }
                        }

                        if (dateDelimiter == DateUtil.Delim.Dot)
                        {
                            if (dateToClean.IndexOf(@".") == -1)
                            {
                                throw new Exception("Invalid date: missing dot delimiter.");
                            }
                        }

                        //This includes Truncate to 33 chars (longest datetime format)
                        dateToClean = SaniCore.NormalizeOrLimit.ToASCIIDateTimesOnly(dateToClean, dateDelimiter, dateDataType, expectTrailingAMorPM);

                        #region Regex checks and strFormat assignment

                        DateRegex dateRegexObj = new DateRegex(SaniCore.CompileRegex);

                        //Perform specific Regex checks where possible after having already normalized the unicode string and reduced it to ASCII-like characters.
                        if ((dateDataType == DateUtil.DataType.Date) && (dateFormat == DateFormat.US)) //Delimiter slash, dash, or dot
                        {
                            strFormat = new string[] { "M/d/yyyy", "MM/dd/yyyy" };                     //Example 6/14/2020

                            if (dateDelimiter == DateUtil.Delim.Dot)
                            {
                                strFormat = new string[] { "M.d.yyyy", "MM.dd.yyyy" };
                            }
                            if (dateDelimiter == DateUtil.Delim.Dash)
                            {
                                strFormat = new string[] { "M-d-yyyy", "MM-dd-yyyy" };
                            }

                            dateRegexObj.PerformRegexForDateInUSFormat(dateToClean);
                        }

                        if ((dateDataType == DateUtil.DataType.Date) && (dateFormat == DateFormat.Euro)) //Delimiter slash, dash, or dot
                        {
                            strFormat = new string[] { "d/M/yyyy", "dd/MM/yyyy" };                       //Example 28/02/2005

                            if (dateDelimiter == DateUtil.Delim.Dot)
                            {
                                strFormat = new string[] { "d.M.yyyy", "dd.MM.yyyy" };
                            }
                            if (dateDelimiter == DateUtil.Delim.Dash)
                            {
                                strFormat = new string[] { "d-M-yyyy", "dd-MM-yyyy" };
                            }

                            dateRegexObj.PerformRegexForDateInEuroFormat(dateToClean);
                        }

                        if ((dateDataType == DateUtil.DataType.Date) && (dateFormat == DateFormat.China)) //Delimiter slash, dash, or dot
                        {
                            strFormat = new string[] { "yyyy/M/d", "yyyy/MM/dd" };                        //Example 2009/6/15

                            if (dateDelimiter == DateUtil.Delim.Dot)
                            {
                                strFormat = new string[] { "yyyy.M.d", "yyyy.MM.dd" };
                            }
                            if (dateDelimiter == DateUtil.Delim.Dash)
                            {
                                strFormat = new string[] { "yyyy-M-d", "yyyy-MM-dd" };
                            }

                            dateRegexObj.PerformRegexForDateInChineseFormat(dateToClean);
                        }

                        //Not the best regex here but we still have DateTime.ParseExact further below.
                        if ((dateDataType == DateUtil.DataType.DateTime) && (dateFormat == DateFormat.US)) //Delimiter slash, dash, or dot
                        {
                            strFormat = null;                                                              //Example 02/18/1753 15:15  NOTE: capital H indicates 24-hour time.

                            if (dateDelimiter == DateUtil.Delim.ForwardSlash)
                            {
                                strFormat = new string[] { "M/d/yyyy H:m", "MM/dd/yyyy H:m" };
                            }
                            if (dateDelimiter == DateUtil.Delim.Dot)
                            {
                                strFormat = new string[] { "M.d.yyyy H:m", "MM.dd.yyyy H:m" };
                            }
                            if (dateDelimiter == DateUtil.Delim.Dash)
                            {
                                strFormat = new string[] { "M-d-yyyy H:m", "MM-dd-yyyy H:m" };
                            }

                            dateRegexObj.PerformRegexForDateTimeInUSFormat(dateToClean);
                        }

                        //Not the best regex here but we still have DateTime.ParseExact further below.
                        if ((dateDataType == DateUtil.DataType.DateTimeWithSeconds) && (dateFormat == DateFormat.US) && !(dateDelimiter == DateUtil.Delim.UTCWithDelimiters || dateDelimiter == DateUtil.Delim.UTCWithoutDelimiters || dateDelimiter == DateUtil.Delim.UTCWithDelimitersAndZone)) //Delimiter slash, dash, or dot
                        {
                            strFormat = null;                                                                                                                                                                                                                                                     //Example 06/05/2009 15:15:33 or 06/05/2009 03:15:33 PM

                            //Date in US format with single space H:m:ss and with optional AM or PM
                            if (expectTrailingAMorPM == false)
                            {
                                if (dateDelimiter == DateUtil.Delim.ForwardSlash) //NOTE: capital H indicates 24-hour time.
                                {
                                    strFormat = new string[] { "M/d/yyyy H:m:s", "MM/dd/yyyy H:m:s" };
                                }
                                if (dateDelimiter == DateUtil.Delim.Dot)
                                {
                                    strFormat = new string[] { "M.d.yyyy H:m:s", "MM.dd.yyyy H:m:s" };
                                }
                                if (dateDelimiter == DateUtil.Delim.Dash)
                                {
                                    strFormat = new string[] { "M-d-yyyy H:m:s", "MM-dd-yyyy H:m:s" };
                                }
                            }
                            else //expect AM or PM
                            {
                                if (dateDelimiter == DateUtil.Delim.ForwardSlash) //NOTE: capital h indicates regular time not military.
                                {
                                    strFormat = new string[] { "M/d/yyyy h:m:s tt", "M/d/yyyy hh:mm:ss tt", "MM/dd/yyyy h:m:s tt", "MM/dd/yyyy hh:mm:ss tt" };
                                }
                                if (dateDelimiter == DateUtil.Delim.Dot)
                                {
                                    strFormat = new string[] { "M.d.yyyy h:m:s tt", "M.d.yyyy hh:mm:ss tt", "MM.dd.yyyy h:m:s tt", "MM.dd.yyyy hh:mm:ss tt" };
                                }
                                if (dateDelimiter == DateUtil.Delim.Dash)
                                {
                                    strFormat = new string[] { "M-d-yyyy h:m:s tt", "M-d-yyyy hh:mm:ss tt", "MM-dd-yyyy h:m:s tt", "MM-dd-yyyy hh:mm:ss tt" };
                                }
                            }

                            dateRegexObj.PerformRegexForDateTimeWithSecondsInUSFormat(dateToClean, expectTrailingAMorPM);
                        }

                        //Not the best regex here but we still have DateTime.ParseExact further below.
                        if ((dateDataType == DateUtil.DataType.DateTimeWithMilliseconds) && (dateFormat == DateFormat.US)) //Delimiter slash, dash, or dot
                        {
                            strFormat = null;                                                                              //Example 06/05/2009 15:15:33.001 OR 06/05/2009 03:05:03.003 PM

                            //Date in US format with single space H:m:ss.fff and with optional AM or PM

                            //NOTE: M = single-digit month is formatted WITHOUT a leading zero. MM = single-digit month is formatted WITH a leading zero.
                            //      H = single-digit hour is formatted WITHOUT a leading zero.  HH = single-digit hour is formatted WITH a leading zero.
                            //      d = single-digit day is formatted WITHOUT a leading zero.   dd = single-digit day is formatted WITH a leading zero.
                            if (expectTrailingAMorPM == false)
                            {
                                if (dateDelimiter == DateUtil.Delim.ForwardSlash) //NOTE: capital H indicates 24-hour time.
                                {
                                    strFormat = new string[] { "M/d/yyyy H:m:s.fff", "MM/dd/yyyy H:m:s.fff", "MM/dd/yyyy HH:mm:ss.fff", "M/d/yyyy HH:m:s.fff" };
                                }
                                if (dateDelimiter == DateUtil.Delim.Dot)
                                {
                                    strFormat = new string[] { "M.d.yyyy H:m:s.fff", "MM.dd.yyyy H:m:s.fff", "MM.dd.yyyy HH:mm:ss.fff", "M.d.yyyy HH:m:s.fff" };
                                }
                                if (dateDelimiter == DateUtil.Delim.Dash)
                                {
                                    strFormat = new string[] { "M-d-yyyy H:m:s.fff", "MM-dd-yyyy H:m:s.fff", "MM-dd-yyyy HH:mm:ss.fff", "M-d-yyyy HH:m:s.fff" };
                                }
                            }
                            else //expect AM or PM
                            {
                                if (dateDelimiter == DateUtil.Delim.ForwardSlash) //NOTE: capital h indicates regular time not military.
                                {
                                    strFormat = new string[] { "M/d/yyyy h:m:s.fff tt", "M/d/yyyy hh:mm:ss.fff tt", "MM/dd/yyyy h:m:s.fff tt", "MM/dd/yyyy hh:mm:ss.fff tt" };
                                }
                                if (dateDelimiter == DateUtil.Delim.Dot)
                                {
                                    strFormat = new string[] { "M.d.yyyy h:m:s.fff tt", "M.d.yyyy hh:mm:ss.fff tt", "MM.dd.yyyy h:m:s.fff tt", "MM.dd.yyyy hh:mm:ss.fff tt" };
                                }
                                if (dateDelimiter == DateUtil.Delim.Dash)
                                {
                                    strFormat = new string[] { "M-d-yyyy h:m:s.fff tt", "M-d-yyyy hh:mm:ss.fff tt", "MM-dd-yyyy h:m:s.fff tt", "MM-dd-yyyy hh:mm:ss.fff tt" };
                                }
                            }

                            dateRegexObj.PerformRegexForDateTimeWithMillisecondsInUSFormat(dateToClean, expectTrailingAMorPM);
                        }

                        if ((dateDataType == DateUtil.DataType.SQLServerDateTime) && (dateFormat == DateFormat.SQLServer)) //Delimiter slash, dash, or dot
                        {
                            strFormat = strFormat = new string[] { "yyyy-MM-dd H:m:s.fff", "yyyy-MM-dd HH:mm:ss.fff" };    //Example 2019-01-25 16:01:36.000

                            //Date in SQL Server format
                            dateRegexObj.PerformRegexForDateTimeInSQLServerFormat(dateToClean);
                        }

                        if (dateDelimiter == DateUtil.Delim.UTCWithDelimiters)
                        {
                            //Example 2015-12-08T15:15:19
                            strFormat = new string[] { "yyyy-MM-dd'T'H:m:s", "yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-dd'T'H:m:s'Z'", "yyyy-MM-dd'T'HH:mm:ss'Z'" };

                            dateRegexObj.PerformRegexForDateTimeWithSecondsAsUTCWithDelimiters(dateToClean);
                        }

                        if (dateDelimiter == DateUtil.Delim.UTCWithDelimitersAndZone)
                        {
                            //Example 2020-06-10T22:03:15-05:00
                            strFormat = new string[] { "yyyy-MM-dd'T'H:m:sK", "yyyy-MM-dd'T'HH:mm:ssK", "yyyy-MM-dd'T'H:m:sK'Z'", "yyyy-MM-dd'T'HH:mm:ssK'Z'" };
                            dateRegexObj.PerformRegexForDateTimeWithSecondsAsUTCWithDelimitersAndZone(dateToClean);
                        }

                        if (dateDelimiter == DateUtil.Delim.UTCWithoutDelimiters)
                        {
                            strFormat = new string[] { "yyyyMMdd'T'HHmmss", "yyyyMMdd'T'Hms", "yyyyMd'T'Hms" }; //Example 20151208T151519

                            //TODO: support yyyyMMdd'T'HHmmss.SSSZ with Milliseconds ?!?

                            dateRegexObj.PerformRegexForDateTimeWithSecondsAsUTCWithoutDelimiters(dateToClean);
                        }
                        #endregion

                        CultureInfo culture = null;

                        if (dateFormat == DateFormat.US || dateFormat == DateFormat.SQLServer) //Example 6/15/2009 1:45:30 PM
                        {
                            culture = CultureInfo.CreateSpecificCulture("en-US");
                        }

                        if (dateFormat == DateFormat.Euro)                        //Example 15/06/2009 13:45:30
                        {
                            culture = CultureInfo.CreateSpecificCulture("es-ES"); //Spain
                        }

                        if (dateFormat == DateFormat.China)                       //Example 2009/6/15 13:45:30
                        {
                            culture = CultureInfo.CreateSpecificCulture("zh-CN"); //China
                        }

                        try
                        {
                            value = DateTime.ParseExact(dateToClean, strFormat, culture, DateTimeStyles.None);
                        }
                        catch (FormatException)
                        {
                            throw new Exception("Unable to parse date.");
                        }

                        //SOURCE: https://blog.submain.com/4-common-datetime-mistakes-c-avoid/
                        if (DateTime.Compare(value.ToUniversalTime(), dateMinValue.ToUniversalTime()) < 0) //convert to utc prior to comparison
                        {
                            tmpResult = dateMinValue;                                                      //if minimum needs to be applied then apply it.
                        }
                        else //check for maximum
                        {
                            if (DateTime.Compare(value.ToUniversalTime(), dateMaxValue.ToUniversalTime()) > 0)
                            {
                                tmpResult = dateMaxValue;
                            }
                            else
                            {
                                tmpResult = value;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    SaniExceptionHandler.TrackOrThrowException(TruncateLength, SaniType, SaniCore, "MinMax: ", "Error datetime to valid MinMax value: ", dateToClean, ex);
                }
                return(tmpResult);
            }
示例#11
0
            /// <summary>
            /// ToValidValue - enforce max and min value of a nullable decimal
            /// SOURCE: https://stackoverflow.com/questions/3115678/converting-string-to-int-using-c-sharp
            /// </summary>
            /// <param name="decimalToClean"></param>
            /// <returns></returns>
            public decimal?ToValidValue(string decimalToClean, decimal decimalMaxValue, decimal decimalMinValue, bool allowNegativeSign, CurrencySeparators currencySeparators = CurrencySeparators.xCommaxDotx)
            {
                decimal?tmpResult = 0;

                try
                {
                    if (String.IsNullOrWhiteSpace(decimalToClean))
                    {
                        tmpResult = null; //Always return null. Protects against a gigabyte of whitespace!!!
                    }
                    else
                    {
                        decimal value;

                        if (Math.Min(decimalMaxValue, decimalMinValue) == decimalMaxValue)
                        {
                            throw new Exception("Invalid parameters: minimum value cannot be greater than the maximum value.");
                        }

                        if (!allowNegativeSign)
                        {
                            if (decimalToClean.IndexOf("-") > -1)
                            {
                                throw new Exception("Negative Sign is NOT allowed.");
                            }
                        }

                        StringComparison ic = StringComparison.OrdinalIgnoreCase;

                        //decimalToClean = RemoveAnyExpectedCurrencySymbols(decimalToClean, currencyType, ic);

                        //Remove these rare occurences
                        decimalToClean = Replace(decimalToClean, "%", String.Empty, ic);         //Percent
                        decimalToClean = Replace(decimalToClean, "NaN", String.Empty, ic);       //NaNSymbol
                        decimalToClean = Replace(decimalToClean, "‰", String.Empty, ic);         //PerMilleSymbol
                        decimalToClean = Replace(decimalToClean, "Infinity", String.Empty, ic);  //PositiveInfinitySymbol
                        decimalToClean = Replace(decimalToClean, "+", String.Empty, ic);         //PositiveSign
                        decimalToClean = Replace(decimalToClean, "-Infinity", String.Empty, ic); //NegativeInfinitySymbol

                        decimalToClean = SaniCore.NormalizeOrLimit.ToASCIINumbersOnly(decimalToClean, true, true, allowNegativeSign, true);

                        NumberStyles styles  = NumberStyles.Currency;
                        CultureInfo  culture = null;

                        if (currencySeparators == CurrencySeparators.xCommaxDotx)
                        {
                            culture = CultureInfo.CreateSpecificCulture("en-US");

                            culture.NumberFormat.CurrencyGroupSeparator = ",";
                            culture.NumberFormat.NumberGroupSeparator   = ",";
                            culture.NumberFormat.PercentGroupSeparator  = ",";

                            culture.NumberFormat.CurrencyDecimalSeparator = ".";
                            culture.NumberFormat.NumberDecimalSeparator   = ".";
                            culture.NumberFormat.PercentDecimalSeparator  = ".";
                        }

                        if (currencySeparators == CurrencySeparators.xDotxCommax)
                        {
                            culture = CultureInfo.CreateSpecificCulture("es-ES");//Spain

                            culture.NumberFormat.CurrencyGroupSeparator = ".";
                            culture.NumberFormat.NumberGroupSeparator   = ".";
                            culture.NumberFormat.PercentGroupSeparator  = ".";

                            culture.NumberFormat.CurrencyDecimalSeparator = ",";
                            culture.NumberFormat.NumberDecimalSeparator   = ",";
                            culture.NumberFormat.PercentDecimalSeparator  = ",";
                        }

                        if (currencySeparators == CurrencySeparators.xSpacexDotx)
                        {
                            culture = CultureInfo.CreateSpecificCulture("sv-SE");//Sweden

                            culture.NumberFormat.CurrencyGroupSeparator = " ";
                            culture.NumberFormat.NumberGroupSeparator   = " ";
                            culture.NumberFormat.PercentGroupSeparator  = " ";

                            culture.NumberFormat.CurrencyDecimalSeparator = ".";
                            culture.NumberFormat.NumberDecimalSeparator   = ".";
                            culture.NumberFormat.PercentDecimalSeparator  = ".";
                        }

                        if (currencySeparators == CurrencySeparators.xSpacexCommax)
                        {
                            culture = CultureInfo.CreateSpecificCulture("fr-FR");//France

                            culture.NumberFormat.CurrencyGroupSeparator = " ";
                            culture.NumberFormat.NumberGroupSeparator   = " ";
                            culture.NumberFormat.PercentGroupSeparator  = " ";

                            culture.NumberFormat.CurrencyDecimalSeparator = ",";
                            culture.NumberFormat.NumberDecimalSeparator   = ",";
                            culture.NumberFormat.PercentDecimalSeparator  = ",";
                        }

                        culture.NumberFormat.NegativeSign = "-";
                        styles = (allowNegativeSign) ? (styles | NumberStyles.AllowLeadingSign) : styles;

                        bool isSuccess = decimal.TryParse(decimalToClean, styles, culture, out value);
                        if (isSuccess)
                        {
                            if (Math.Min(value, decimalMinValue) == value)
                            {
                                tmpResult = decimalMinValue;//if min value has to be applied then apply it.
                            }
                            else //otherwise check whether the max value needs to be applied.
                            {
                                if (Math.Max(value, decimalMaxValue) == value)
                                {
                                    tmpResult = decimalMaxValue;
                                }
                                else
                                {
                                    tmpResult = value;
                                }
                            }
                        }
                        else
                        {
                            throw new Exception("Parse Failure.");
                        }
                    }
                }
                catch (Exception ex)
                {
                    SaniExceptionHandler.TrackOrThrowException(TruncateLength, SaniType, SaniCore, "MinMax: ", "Error decimal to valid MinMax value: ", decimalToClean, ex);
                }
                return(tmpResult);
            }
示例#12
0
        /// <summary>
        /// Limit a Unicode string to just the limited subset of ASCII-compatible characters.
        /// </summary>
        /// <param name="strToClean"></param>
        /// <returns></returns>
        public string ToASCIIOnly(string strToClean)
        {
            string tmpResult     = String.Empty;
            bool   removeAccents = true;

            try
            {
                if (string.IsNullOrWhiteSpace(strToClean))
                {
                    tmpResult = null; //Always return null. Protects against a gigabyte of whitespace!!!
                }
                else
                {
                    tmpResult = strToClean.Normalize(NormalizationForm.FormKC);

                    //SOURCES:
                    //https://stackoverflow.com/questions/1008802/converting-symbols-accent-letters-to-english-alphabet
                    //http://www.codecodex.com/wiki/Unaccent_letters
                    //http://www.unicode.org/Public/security/latest/confusables.txt
                    //https://stackoverflow.com/questions/4846365/find-characters-that-are-similar-glyphically-in-unicode

                    if (removeAccents)
                    {
                        string PLAIN_ASCII =
                            "AaEeIiOoUu"     // grave ` (U+0060)
                            + "AaEeIiOoUuYy" // acute ´ (U+00B4)
                            + "AaEeIiOoUuYy" // circumflex ^ (U+005E)
                            + "AaOoNn"       // tilde ~ (U+007E) [Most frequent in Spanish such as "español".]
                            + "AaEeIiOoUuYy" // diaeresis or umlaut ̈	 (U+0308)
                            + "AaUu"         // ring ̊  (U+030A) [Most frequent Danish or Swedish Å, but also potentially Ů in Czech.]
                            + "Cc"           // cedilla ̧  (U+00B8) [Most frequent character with cedilla is "ç" such as in "façade".]
                            + "OoUu";        // double acute ̋   (U+030B) [Most frequent in Hungarian for Ő and Ű.]

                        //For example, handles: Ù, Ú, Û, ñ, Ü, Ů, ç, Ű

                        //TODO: Add support for the following: Ū, Ŭ

                        //Does NOT currently support the following diacritical chars: Ư, Ǔ, Ǖ, Ǘ, Ǚ, Ǜ, Ủ, Ứ, Ừ, Ử, Ữ, Ự";

                        string UNICODE =
                            "\u00C0\u00E0\u00C8\u00E8\u00CC\u00EC\u00D2\u00F2\u00D9\u00F9"
                            + "\u00C1\u00E1\u00C9\u00E9\u00CD\u00ED\u00D3\u00F3\u00DA\u00FA\u00DD\u00FD"
                            + "\u00C2\u00E2\u00CA\u00EA\u00CE\u00EE\u00D4\u00F4\u00DB\u00FB\u0176\u0177"
                            + "\u00C3\u00E3\u00D5\u00F5\u00D1\u00F1"
                            + "\u00C4\u00E4\u00CB\u00EB\u00CF\u00EF\u00D6\u00F6\u00DC\u00FC\u0178\u00FF"
                            + "\u00C5\u00E5\u016E\u016F"
                            + "\u00C7\u00E7"
                            + "\u0150\u0151\u0170\u0171"
                        ;

                        // remove accentuated from a string and replace with ascii equivalent
                        StringBuilder sb = new StringBuilder();

                        int n = tmpResult.Length;
                        for (int i = 0; i < n; i++)
                        {
                            char c   = tmpResult.ToCharArray()[i];
                            int  pos = UNICODE.IndexOf(c);
                            if (pos > -1)
                            {
                                sb.Append(PLAIN_ASCII.ToCharArray()[pos]);
                            }
                            else
                            {
                                sb.Append(c);
                            }
                        }
                        tmpResult = sb.ToString();

                        //THIS WILL LIMIT TO A SUBSET OF ASCII CHARACTERS. THIS WILL REMOVE ANY DIACRITIC, TABS, NEW LINE CHARACTERS!!
                        tmpResult = (new string(tmpResult.ToCharArray().Where(c => (32 <= (int)c && (int)c <= 126)).ToArray()));
                    }
                }
            }
            catch (Exception ex)
            {
                SaniExceptionHandler.TrackOrThrowException(TruncateLength, SaniType, SaniCore, "NormalizeOrLimit: ", "Error limiting unicode to ASCII: ", strToClean, ex);
            }
            return(tmpResult);
        }
示例#13
0
        /// <summary>
        /// Limit a Unicode string to just the limited subset of ASCII-compatible date times only, aka Latin numbers with date and time delimiters.
        /// </summary>
        /// <param name="strToClean"></param>
        /// <returns></returns>
        public string ToASCIIDateTimesOnly(string strToClean, DateUtil.Delim delimiter, DateUtil.DataType dateDataType, bool allowAMandPM)
        {
            string tmpResult = String.Empty;

            if (dateDataType == DateUtil.DataType.SQLServerDateTime)
            {
                dateDataType = DateUtil.DataType.DateTimeWithMilliseconds; //retain colon and space
            }

            try
            {
                if (string.IsNullOrWhiteSpace(strToClean))
                {
                    tmpResult = null; //Always return null. Protects against a gigabyte of whitespace!!!
                }
                else
                {
                    tmpResult = SaniCore.Truncate.ToValidLength(strToClean, 33);
                    tmpResult = tmpResult.Normalize(NormalizationForm.FormKC);//just to be extra safe

                    //Example 12-8-2015 15:15
                    if (delimiter == DateUtil.Delim.Dash && !(delimiter == DateUtil.Delim.UTCWithDelimiters || delimiter == DateUtil.Delim.UTCWithoutDelimiters || delimiter == DateUtil.Delim.UTCWithDelimitersAndZone))
                    {
                        tmpResult = (new string(tmpResult.ToCharArray().Where(c => ((48 <= (int)c && (int)c <= 57) || //Latin numbers
                                                                                    ((int)c == 45) || //45 = dash
                                                                                    (allowAMandPM ? (((int)c == 65) || ((int)c == 77) || ((int)c == 80) || ((int)c == 97) || ((int)c == 109) || ((int)c == 112)) : false) || //65 = A , 77 = M, 80 = P, 97 = a, 109 = m, 112 = p
                                                                                    ((dateDataType == DateUtil.DataType.DateTime || dateDataType == DateUtil.DataType.DateTimeWithSeconds || dateDataType == DateUtil.DataType.DateTimeWithMilliseconds) ? ((int)c == 32) : false) || //32 = space
                                                                                    ((dateDataType == DateUtil.DataType.DateTime || dateDataType == DateUtil.DataType.DateTimeWithSeconds || dateDataType == DateUtil.DataType.DateTimeWithMilliseconds) ? ((int)c == 58) : false) || //58 = colon
                                                                                    ((dateDataType == DateUtil.DataType.DateTimeWithMilliseconds) ? ((int)c == 46) : false) //46 = dot
                                                                                    )).ToArray()));
                    }

                    //Example 12.8.2015 15:15
                    if (delimiter == DateUtil.Delim.Dot && !(delimiter == DateUtil.Delim.UTCWithDelimiters || delimiter == DateUtil.Delim.UTCWithoutDelimiters || delimiter == DateUtil.Delim.UTCWithDelimitersAndZone))
                    {
                        tmpResult = (new string(tmpResult.ToCharArray().Where(c => ((48 <= (int)c && (int)c <= 57) ||
                                                                                    ((int)c == 46) || //46 = dot
                                                                                    (allowAMandPM ? (((int)c == 65) || ((int)c == 77) || ((int)c == 80) || ((int)c == 97) || ((int)c == 109) || ((int)c == 112)) : false) || //65 = A , 77 = M, 80 = P, 97 = a, 109 = m, 112 = p
                                                                                    ((dateDataType == DateUtil.DataType.DateTime || dateDataType == DateUtil.DataType.DateTimeWithSeconds || dateDataType == DateUtil.DataType.DateTimeWithMilliseconds) ? ((int)c == 32) : false) || //32 = space
                                                                                    ((dateDataType == DateUtil.DataType.DateTime || dateDataType == DateUtil.DataType.DateTimeWithSeconds || dateDataType == DateUtil.DataType.DateTimeWithMilliseconds) ? ((int)c == 58) : false) //58 = colon
                                                                                    )).ToArray()));
                    }

                    //Example 12/8/2015 15:15
                    if (delimiter == DateUtil.Delim.ForwardSlash && !(delimiter == DateUtil.Delim.UTCWithDelimiters || delimiter == DateUtil.Delim.UTCWithoutDelimiters || delimiter == DateUtil.Delim.UTCWithDelimitersAndZone))
                    {
                        tmpResult = (new string(tmpResult.ToCharArray().Where(c => ((48 <= (int)c && (int)c <= 57) ||
                                                                                    ((int)c == 47) || //47 = forward slash
                                                                                    (allowAMandPM ? (((int)c == 65) || ((int)c == 77) || ((int)c == 80) || ((int)c == 97) || ((int)c == 109) || ((int)c == 112)) : false) || //65 = A , 77 = M, 80 = P, 97 = a, 109 = m, 112 = p
                                                                                    ((dateDataType == DateUtil.DataType.DateTime || dateDataType == DateUtil.DataType.DateTimeWithSeconds || dateDataType == DateUtil.DataType.DateTimeWithMilliseconds) ? ((int)c == 32) : false) || //32 = space
                                                                                    ((dateDataType == DateUtil.DataType.DateTime || dateDataType == DateUtil.DataType.DateTimeWithSeconds || dateDataType == DateUtil.DataType.DateTimeWithMilliseconds) ? ((int)c == 58) : false) || //58 = colon
                                                                                    ((dateDataType == DateUtil.DataType.DateTimeWithMilliseconds) ? ((int)c == 46) : false) //46 = dot
                                                                                    )).ToArray()));
                    }

                    if (delimiter == DateUtil.Delim.UTCWithoutDelimiters) //yyyyMMdd'T'HHmmss.SSSZ
                    {
                        tmpResult = (new string(tmpResult.ToCharArray().Where(c => ((48 <= (int)c && (int)c <= 57) || //Latin numbers
                                                                                    ((int)c == 46) || //46 = dot
                                                                                    (((int)c == 84) || ((int)c == 90) || ((int)c == 32)) //84 = T, 90 = Z, 32 = space
                                                                                    )).ToArray()));
                    }

                    if (delimiter == DateUtil.Delim.UTCWithDelimitersAndZone) //yyyy-MM-dd'T'HH:mm:ssK EXAMPLE: 2020-06-10T22:03:15-05:00
                    {
                        tmpResult = (new string(tmpResult.ToCharArray().Where(c => ((48 <= (int)c && (int)c <= 57) || //Latin numbers
                                                                                    ((int)c == 45) || //45 = dash and minus sign
                                                                                    ((int)c == 58) || //58 = colon
                                                                                    ((int)c == 43) || //43 = plus sign
                                                                                    (((int)c == 84) || ((int)c == 90) || ((int)c == 32)) //84 = T, 90 = Z, 32 = space
                                                                                    )).ToArray()));
                    }

                    if (delimiter == DateUtil.Delim.UTCWithDelimiters) //yyyy-MM-dd'T'HH:mm:ss.SSSZZ  EXAMPLE: 2014-08-29T06:44:03Z
                    {
                        tmpResult = (new string(tmpResult.ToCharArray().Where(c => ((48 <= (int)c && (int)c <= 57) || //Latin numbers
                                                                                    ((int)c == 45) || //45 = dash
                                                                                    ((int)c == 58) || //58 = colon
                                                                                    (((int)c == 84) || ((int)c == 90) || ((int)c == 32)) //84 = T, 90 = Z, 32 = space
                                                                                    )).ToArray()));
                    }

                    //TODO: support 1995-07-14T13:05:00.0000000-03:00 ?!?
                }
            }
            catch (Exception ex)
            {
                SaniExceptionHandler.TrackOrThrowException(TruncateLength, SaniType, SaniCore, "NormalizeOrLimit: ", "Error limiting unicode to ASCII DateTimes Only: ", strToClean, ex);
            }
            return(tmpResult);
        }
示例#14
0
            /// <summary>
            /// Sanitize FileName Via Regex.
            /// SOURCE: https://stackoverflow.com/questions/11794144/regular-expression-for-valid-filename
            /// SOURCE: https://stackoverflow.com/questions/6730009/validate-a-file-name-on-windows
            /// SOURCE: https://stackoverflow.com/questions/62771/how-do-i-check-if-a-given-string-is-a-legal-valid-file-name-under-windows#62855
            /// </summary>
            /// <param name="strToClean"></param>
            /// <returns></returns>
            public string SanitizeViaRegex(string filename, int maxLength, bool disallowMoreThanOneDot, string optionalWhiteListFileExtension, bool disallowExecutableExtensions, bool disallowWebExtensions, bool disallowOfficeMacroExtensions, bool disallowPDFFileExtensions, bool disallowMediaFileExtensions)
            {
                string tmpResult = String.Empty;

                try
                {
                    if (string.IsNullOrWhiteSpace(filename))
                    {
                        throw new Exception("Filename cannot be null or empty.");
                    }
                    else
                    {
                        tmpResult = SaniCore.Truncate.ToValidLength(filename, maxLength);

                        //check for malicious Unicode prior to normalizing and reducing to ASCII-like characters
                        if (ContainsMaliciousCharacters(ref tmpResult))
                        {
                            throw new Exception("Filename contains potentially malicious characters.");
                        }

                        //normalize prior to checking for dot characters to prevent unicode characters similar to dot
                        tmpResult = SaniCore.NormalizeOrLimit.ToASCIIOnly(tmpResult);

                        //check for dot characters
                        char dot   = '.';
                        int  count = 0;
                        foreach (char letter in tmpResult)
                        {
                            if (letter == dot)
                            {
                                count++;
                            }
                        }

                        if (disallowMoreThanOneDot)
                        {
                            if (count > 1)
                            {
                                throw new Exception("Filename contains more than one dot character.");
                            }
                        }

                        if (count == 0)
                        {
                            throw new Exception("Filename does NOT contain at least one dot character.");
                        }

                        //now apply the regex check after having already normalized the unicode string and reduced it to ASCII-like characters.
                        //This regex will disallow invalid characters within a filename such as ? * : " < > ; | \ / and will not allow a trailing space or dot.
                        string regex2 = @"^(?!^(PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d|\..*)(\..+)?$)[^\x00-\x1f\\?*:\""<>;|\/]+[^*\x00-\x1F\ .]$";

                        bool matchOnWindows = false;
                        if (SaniCore.CompileRegex)
                        {
                            //May cause build to be slower but runtime Regex to be faster . . . let developer choose.
                            matchOnWindows = Regex.IsMatch(tmpResult, regex2, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled);
                        }
                        else
                        {
                            matchOnWindows = Regex.IsMatch(tmpResult, regex2, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
                        }

                        if (!matchOnWindows)
                        {
                            throw new Exception("Filename is NOT a valid Windows filename.");
                        }

                        //now check for dot and file extensions after having already normalized, etc.
                        string[] arrayOfStr = tmpResult.Split('.');
                        string   fileExtensionWithoutTheDot = arrayOfStr[arrayOfStr.Length - 1];
                        string   tmpResultFileExtension     = "." + fileExtensionWithoutTheDot;

                        if (optionalWhiteListFileExtension != null) //compare exclusive here
                        {
                            //If a allowedList file extension was NOT provided and matched then throw an exception.
                            if (!String.Equals(optionalWhiteListFileExtension, tmpResultFileExtension, StringComparison.OrdinalIgnoreCase))
                            {
                                throw new Exception("Filename extension fails to match the allowedList file extension.");
                            }
                        }
                        else
                        {
                            //If no allowedList file extension was provided and if restrictedList options were flagged true, apply the restrictedLists
                            if (disallowExecutableExtensions && ContainsExecutableExtensions(ref tmpResult))
                            {
                                throw new Exception("Filename contains common executable extensions.");
                            }

                            if (disallowWebExtensions && ContainsWebExtensions(ref tmpResult))
                            {
                                throw new Exception("Filename contains common web extensions.");
                            }

                            if (disallowOfficeMacroExtensions && ContainsOfficeMacroExtensions(ref tmpResult))
                            {
                                throw new Exception("Filename contains office file extensions.");
                            }

                            if (disallowPDFFileExtensions && ContainsPDFFileExtensions(ref tmpResult))
                            {
                                throw new Exception("Filename contains PDF file extensions.");
                            }

                            if (disallowMediaFileExtensions && ContainsMediaFileExtensions(ref tmpResult))
                            {
                                throw new Exception("Filename contains Media file extensions.");
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    SaniExceptionHandler.TrackOrThrowException(TruncateLength, SaniType, SaniCore, "FileNameCleanse: ", "Error sanitizing via Regex using ASCII: ", tmpResult, ex);
                }

                return(tmpResult);
            }