System.Number.ParseNumber C# (CSharp) Method

ParseNumber() private static method

private static ParseNumber ( char &str, NumberStyles options, NumberBuffer &number, NumberFormatInfo numfmt, Boolean parseDecimal ) : Boolean
str char
options NumberStyles
number NumberBuffer
numfmt NumberFormatInfo
parseDecimal Boolean
return Boolean
        private unsafe static Boolean ParseNumber(ref char * str, NumberStyles options, ref NumberBuffer number, NumberFormatInfo numfmt, Boolean parseDecimal) {

            const Int32 StateSign = 0x0001;
            const Int32 StateParens = 0x0002;
            const Int32 StateDigits = 0x0004;
            const Int32 StateNonZero = 0x0008;
            const Int32 StateDecimal = 0x0010;
            const Int32 StateCurrency = 0x0020;

            number.scale = 0;
            number.sign = false;
            string decSep;                  // decimal separator from NumberFormatInfo.
            string groupSep;                // group separator from NumberFormatInfo.
            string currSymbol = null;       // currency symbol from NumberFormatInfo.
            // The alternative currency symbol used in Win9x ANSI codepage, that can not roundtrip between ANSI and Unicode.
            // Currently, only ja-JP and ko-KR has non-null values (which is U+005c, backslash)
            string ansicurrSymbol = null;   // currency symbol from NumberFormatInfo.
            string altdecSep = null;        // decimal separator from NumberFormatInfo as a decimal
            string altgroupSep = null;      // group separator from NumberFormatInfo as a decimal

            Boolean parsingCurrency = false; 
            if ((options & NumberStyles.AllowCurrencySymbol) != 0) {
                currSymbol = numfmt.CurrencySymbol;
                if (numfmt.ansiCurrencySymbol != null) {
                    ansicurrSymbol = numfmt.ansiCurrencySymbol;
                }
                // The idea here to match the curreny separators and on failure match the number separators to keep the perf of VB's IsNumeric fast.
                // The values of decSep are setup to use the correct relevant seperator (currency in the if part and decimal in the else part).
                altdecSep = numfmt.NumberDecimalSeparator;
                altgroupSep = numfmt.NumberGroupSeparator;
                decSep = numfmt.CurrencyDecimalSeparator;
                groupSep = numfmt.CurrencyGroupSeparator;
                parsingCurrency = true;
            }
            else {
                decSep = numfmt.NumberDecimalSeparator;
                groupSep = numfmt.NumberGroupSeparator;
            }

            Int32 state = 0;
            Boolean signflag = false; // Cache the results of "options & PARSE_LEADINGSIGN && !(state & STATE_SIGN)" to avoid doing this twice
              
            char* p = str;
            char ch = *p;
            char* next;

            while (true) {
                //Eat whitespace unless we've found a sign which isn't followed by a currency symbol.
                //"-Kr 1231.47" is legal but "- 1231.47" is not.
                if (IsWhite(ch) && ((options & NumberStyles.AllowLeadingWhite) != 0) && (((state & StateSign) == 0) || (((state & StateSign) != 0) && (((state & StateCurrency) != 0) || numfmt.numberNegativePattern == 2)))) {
                    // Do nothing here. We will increase p at the end of the loop.
                }
                else if ((signflag = (((options & NumberStyles.AllowLeadingSign) != 0) && ((state & StateSign) == 0))) && ((next = MatchChars(p, numfmt.positiveSign)) != null)) {
                    state |= StateSign;
                    p = next - 1;
                } else if (signflag && (next = MatchChars(p, numfmt.negativeSign)) != null) {
                    state |= StateSign;
                    number.sign = true;
                    p = next - 1;
                }
                else if (ch == '(' && ((options & NumberStyles.AllowParentheses) != 0) && ((state & StateSign) == 0)) {
                    state |= StateSign | StateParens;
                    number.sign = true;
                }
                else if ((currSymbol != null && (next = MatchChars(p, currSymbol)) != null) || (ansicurrSymbol != null && (next = MatchChars(p, ansicurrSymbol)) != null)) {
                    state |= StateCurrency;
                    currSymbol = null;  
                    ansicurrSymbol = null;  
                    // We already found the currency symbol. There should not be more currency symbols. Set
                    // currSymbol to NULL so that we won't search it again in the later code path.
                    p = next - 1;
                }
                else {
                    break;
                }
                ch = *++p;
            }
            Int32 digCount = 0;
            Int32 digEnd = 0;
            while (true) {
                if ((ch >= '0' && ch <= '9') || (((options & NumberStyles.AllowHexSpecifier) != 0) && ((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')))) {
                    state |= StateDigits;
                    if (ch != '0' || (state & StateNonZero) != 0) {
                        if (digCount < NumberMaxDigits) {
                            number.digits[digCount++] = ch;
                            if (ch != '0' || parseDecimal) {
                                digEnd = digCount;
                            }
                        }
                        if ((state & StateDecimal) == 0) { 
                            number.scale++;
                        }
                        state |= StateNonZero;
                    }
                    else if ((state & StateDecimal) != 0) {
                        number.scale--;
                    }
                }
                else if (((options & NumberStyles.AllowDecimalPoint) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, decSep)) != null || ((parsingCurrency) && (state & StateCurrency) == 0) && (next = MatchChars(p, altdecSep)) != null)) {
                    state |= StateDecimal;
                    p = next - 1;
                }
                else if (((options & NumberStyles.AllowThousands) != 0) && ((state & StateDigits) != 0) && ((state & StateDecimal) == 0) && ((next = MatchChars(p, groupSep)) != null || ((parsingCurrency) && (state & StateCurrency) == 0) && (next = MatchChars(p, altgroupSep)) != null)) {
                    p = next - 1;
                }
                else {
                    break;
                }
                ch = *++p;
            }

            Boolean negExp = false;
            number.precision = digEnd;
            number.digits[digEnd] = '\0';
            if ((state & StateDigits) != 0) {
                if ((ch == 'E' || ch == 'e') && ((options & NumberStyles.AllowExponent) != 0)) {
                    char* temp = p;
                    ch = *++p;
                    if ((next = MatchChars(p, numfmt.positiveSign)) != null) {
                        ch = *(p = next);
                    }
                    else if ((next = MatchChars(p, numfmt.negativeSign)) != null) {
                        ch = *(p = next);
                        negExp = true;
                    }
                    if (ch >= '0' && ch <= '9') {
                        Int32 exp = 0;
                        do {
                            exp = exp * 10 + (ch - '0');
                            ch = *++p;
                            if (exp > 1000) {
                                exp = 9999;
                                while (ch >= '0' && ch <= '9') {
                                    ch = *++p;
                                }
                            }
                        } while (ch >= '0' && ch <= '9');
                        if (negExp) {
                            exp = -exp;
                        }
                        number.scale += exp;
                    }
                    else {
                        p = temp;
                        ch = *p;
                    }
                }
                while (true) {
                    if (IsWhite(ch) && ((options & NumberStyles.AllowTrailingWhite) != 0)) {
                    }
                    else if ((signflag = (((options & NumberStyles.AllowTrailingSign) != 0) && ((state & StateSign) == 0))) && (next = MatchChars(p, numfmt.positiveSign)) != null) {
                        state |= StateSign;
                        p = next - 1;
                    } else if (signflag && (next = MatchChars(p, numfmt.negativeSign)) != null) {
                        state |= StateSign;
                        number.sign = true;
                        p = next - 1;
                    }
                    else if (ch == ')' && ((state & StateParens) != 0)) {
                        state &= ~StateParens;
                    }
                    else if ((currSymbol != null && (next = MatchChars(p, currSymbol)) != null) || (ansicurrSymbol != null && (next = MatchChars(p, ansicurrSymbol)) != null)) {
                        currSymbol = null;
                        ansicurrSymbol = null;
                        p = next - 1;
                    }
                    else {
                        break;
                    }
                    ch = *++p;
                }
                if ((state & StateParens) == 0) {
                    if ((state & StateNonZero) == 0) {
                        if (!parseDecimal) {
                            number.scale = 0;
                        }
                        if ((state & StateDecimal) == 0) {
                            number.sign = false;
                        }
                    }
                    str = p;
                    return true;
                }
            }
            str = p;
            return false;
        }

Usage Example

        internal unsafe static bool TryStringToNumber(string str, NumberStyles options, ref Number.NumberBuffer number, StringBuilder sb, NumberFormatInfo numfmt, bool parseDecimal)
        {
            if (str == null)
            {
                return(false);
            }

            fixed(string text = str)
            {
                char *ptr = text;

                if (ptr != null)
                {
                    ptr += RuntimeHelpers.OffsetToStringData / 2;
                }
                char *ptr2 = ptr;

                if (!Number.ParseNumber(ref ptr2, options, ref number, sb, numfmt, parseDecimal) || ((long)(ptr2 - ptr) < (long)str.Length && !Number.TrailingZeros(str, (int)((long)(ptr2 - ptr)))))
                {
                    return(false);
                }
            }

            return(true);
        }
All Usage Examples Of System.Number::ParseNumber