[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Dotgnu-pnet-commits] CVS: pnetlib/runtime/System/Private NumberParser.
From: |
Jonathan Springer <address@hidden> |
Subject: |
[Dotgnu-pnet-commits] CVS: pnetlib/runtime/System/Private NumberParser.cs,1.3,1.4 |
Date: |
Wed, 01 Jan 2003 13:13:00 -0500 |
Update of /cvsroot/dotgnu-pnet/pnetlib/runtime/System/Private
In directory subversions:/tmp/cvs-serv3152/runtime/System/Private
Modified Files:
NumberParser.cs
Log Message:
Support for parsing floating-point and decimal numbers.
Index: NumberParser.cs
===================================================================
RCS file: /cvsroot/dotgnu-pnet/pnetlib/runtime/System/Private/NumberParser.cs,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -r1.3 -r1.4
*** NumberParser.cs 28 Nov 2001 04:22:39 -0000 1.3
--- NumberParser.cs 1 Jan 2003 18:12:58 -0000 1.4
***************
*** 24,27 ****
--- 24,28 ----
using System;
using System.Globalization;
+ using System.Text;
internal sealed class NumberParser
***************
*** 689,696 ****
}
public static Decimal ParseDecimal(String s, NumberStyles style,
NumberFormatInfo nfi)
{
! return 0.0m;
}
--- 690,1087 ----
}
+ private static string RawHandleWhite(String s,
+ NumberStyles style,
NumberFormatInfo nfi)
+ {
+ String ret;
+ if ((style & NumberStyles.AllowLeadingWhite) != 0 &&
+ (style & NumberStyles.AllowTrailingWhite) != 0)
+ {
+ ret = s.Trim();
+ }
+ else if ((style & NumberStyles.AllowLeadingWhite) != 0)
+ {
+ ret = s.TrimStart(null);
+ if (ret.Length > s.TrimEnd(null).Length)
+ throw new
FormatException(_("Format_UnallowedTrailingWhite"));
+ }
+ else if ((style & NumberStyles.AllowTrailingWhite) != 0)
+ {
+ ret = s.TrimEnd(null);
+ if (ret.Length > s.TrimStart(null).Length)
+ throw new
FormatException(_("Format_UnallowedLeadingWhite"));
+ }
+ else
+ {
+ ret = s;
+ if (ret.Length > s.TrimStart(null).Length)
+ throw new
FormatException(_("Format_UnallowedLeadingWhite"));
+ if (ret.Length > s.TrimEnd(null).Length)
+ throw new
FormatException(_("Format_UnallowedTrailingWhite"));
+ }
+ return ret;
+ }
+
+ private static void RawHandleSign(StringBuilder sb,
+ NumberStyles style,
NumberFormatInfo nfi)
+ {
+ bool leadingsign, trailingsign;
+
+ if (sb.ToString().StartsWith(nfi.PositiveSign) ||
+ sb.ToString().StartsWith(nfi.NegativeSign))
+ {
+ leadingsign = true;
+ if ((style & NumberStyles.AllowLeadingSign) == 0)
+ throw new
FormatException(_("Format_UnallowedLeadingSign"));
+ }
+
+ if (sb.ToString().EndsWith(nfi.PositiveSign) ||
+ sb.ToString().EndsWith(nfi.NegativeSign))
+ {
+ trailingsign = true;
+ if ((style & NumberStyles.AllowTrailingSign) == 0)
+ throw new
FormatException(_("Format_UnallowedTrailingSign"));
+ }
+
+ if (leadingsign && trailingsign)
+ {
+ throw new FormatException(_("Format_TwoSigns"));
+ }
+ }
+
+ private static void RawHandleCurrencySymbol(StringBuilder sb,
+ NumberStyles style,
NumberFormatInfo nfi)
+ {
+ int symbolPos = sb.ToString().IndexOf(nfi.CurrencySymbol);
+
+ // Nothing to be done
+ if (symbolPos == -1) return;
+
+ if ((style & NumberStyles.AllowCurrencySymbol) != 0)
+ {
+ // Remove the currency symbol
+ sb.Remove(symbolPos,nfi.CurrencySymbol.Length);
+ }
+ else
+ {
+ // Throw a format exception
+ throw new
FormatException(_("Format_UnallowedCurrencySymbol"));
+ }
+ }
+
+ private static void RawHandleDecimalPoint(StringBuilder sb,
+ NumberStyles
style, NumberFormatInfo nfi)
+ {
+ // There are three different possible decimal points,
+ // of which only one should be present.
+
+ // Change all possible decimal points into one.
+ sb.Replace(nfi.CurrencyDecimalSeparator,
nfi.NumberDecimalSeparator);
+ sb.Replace(nfi.PercentDecimalSeparator,
nfi.NumberDecimalSeparator);
+
+ int decimalPos =
sb.ToString().IndexOf(nfi.NumberDecimalSeparator);
+
+ if ((style & NumberStyles.AllowDecimalPoint) != 0)
+ {
+ // Test for multiple decimal points
+ if (decimalPos
+ !=
sb.ToString().LastIndexOf(nfi.NumberDecimalSeparator))
+ {
+ throw
+ new
FormatException(_("Format_MultipleDecimalSeparators"));
+ }
+ }
+ else if (decimalPos > -1)
+ {
+ throw new
FormatException(_("Format_UnallowedDecimalPoint"));
+ }
+ }
+
+ private static readonly char [] Ee = {'e', 'E'};
+
+ private static void RawHandleExponent(StringBuilder sb,
+ NumberStyles style,
NumberFormatInfo nfi)
+ {
+ string s = sb.ToString();
+ int ePos = s.IndexOfAny(Ee);
+ int decimalPos = s.IndexOf(nfi.NumberDecimalSeparator);
+ int i;
+
+ // Bail out if this doesn't look like an exponential number
+ if (ePos != s.LastIndexOfAny(Ee)) return;
+ if (decimalPos >= ePos) return;
+
+ // Exponent is a leading sign plus at least one digit
+ if (ePos+1 >= s.Length) return;
+ if (s[ePos+1] != '+' && s[ePos+1] != '-') return;
+
+ if (ePos + 3 >= s.Length) return; // Have to have at least one
digit
+ for (i = ePos + 2; i < s.Length; i++)
+ {
+ if (s[i] < '0' || s[i] > '9') return;
+ }
+
+ for (i = ePos - 1;
+ i >= decimalPos +
nfi.NumberDecimalSeparator.Length;
+ i--)
+ {
+ if (s[i] < '0' || s[i] > '9') return;
+ }
+
+ for (i = decimalPos-1;
+ i <= '-' && i >= 0;
+ i--)
+ {
+ if (s[i] < '0' || s[i] > '9') return;
+ }
+
+ if (i >= nfi.NegativeSign.Length)
+ {
+ return;
+ }
+ else if (i >= 0 && !s.StartsWith(nfi.NegativeSign))
+ {
+ return;
+ }
+
+ // Okay, this is an exponent. Is it allowable?
+ if ((style & NumberStyles.AllowExponent) == 0)
+ {
+ throw new
FormatException(_("Format_UnallowedExponent"));
+ }
+ }
+
+ private static void RawHandleParentheses(StringBuilder sb,
+ NumberStyles style,
NumberFormatInfo nfi)
+ {
+ int startPos = sb.ToString().IndexOf('(');
+ int endPos = sb.ToString().IndexOf(')');
+
+ // Move along... Nothing to see here...
+ if (startPos == -1 && endPos == -1) return;
+
+ if (startPos == -1 || endPos == -1 || startPos > endPos)
+ throw new
FormatException(_("Format_UnbalancedParentheses"));
+
+ if ((style & NumberStyles.AllowParentheses) != 0)
+ {
+ // Replace parentheses with a leading
NumberNegativeSign
+ sb.Remove(startPos,1);
+ sb.Remove(endPos,1);
+ sb.Insert(0, nfi.NegativeSign);
+
+ // Test for additional parentheses... Bad!
+ if (sb.ToString().IndexOf('(') != -1 ||
+ sb.ToString().IndexOf(')') != -1)
+ {
+ throw new
FormatException(_("Format_ExtraParentheses"));
+ }
+ }
+ else
+ {
+ throw new
FormatException(_("Format_UnallowedParentheses"));
+ }
+ }
+
+ private static bool RawHandleThousandsTry(StringBuilder sb,
+ NumberFormatInfo nfi, string sep, int [] sizes)
+ {
+ int i, idx;
+
+ i = 0;
+ idx = sb.ToString().IndexOf(nfi.NumberDecimalSeparator);
+ idx -= sep.Length;
+ idx -= sizes[i];
+
+ while (idx > 0)
+ {
+ if (sb.ToString(idx, sep.Length) != sep) return false;
+
+ sb.Remove(idx, sep.Length);
+
+ if (i < sizes.Length - 1) i++;
+ idx -= sizes[i];
+ }
+
+ return true;
+ }
+
+ private static string RawHandleThousands(StringBuilder sb,
+ NumberStyles style, NumberFormatInfo nfi)
+ {
+ // Once again, the specification has three possible sets of
+ // group separators that could be used here. This routine
+ // tries each in turn until one works, then decides what to
+ // do about it.
+
+ bool ok;
+ StringBuilder hold;
+
+ hold = new StringBuilder(sb.ToString());
+ ok = RawHandleThousandsTry(hold, nfi,
+ nfi.NumberGroupSeparator, nfi.NumberGroupSizes);
+
+ if (!ok)
+ {
+ hold = new StringBuilder(sb.ToString());
+ ok = RawHandleThousandsTry(hold, nfi,
+ nfi.CurrencyGroupSeparator,
nfi.CurrencyGroupSizes);
+ }
+
+ if (!ok)
+ {
+ hold = new StringBuilder(sb.ToString());
+ ok = RawHandleThousandsTry(hold, nfi,
+ nfi.PercentGroupSeparator,
nfi.PercentGroupSizes);
+ }
+
+ if (!ok) return sb.ToString();
+
+ // At this point, we know we CAN separate the groups. Now the
+ // question is, "Should we?"
+ if ((style & NumberStyles.AllowThousands) != 0)
+ {
+ return hold.ToString();
+ }
+ else
+ {
+ throw new FormatException("Format_UnallowedThousands");
+ }
+ }
+
+ private static string RawString(String s, NumberStyles style,
+
NumberFormatInfo nfi)
+ {
+ // Bail out and let the parser cope -- poor parser...
+ if ((style & NumberStyles.AllowHexSpecifier) != 0) return s;
+
+ // These routines hold a significant amount of subjective
+ // format validation. They also cleanse out information
+ // unneeded by the parser itself (e.g. whitespace, group).
+ StringBuilder sb =
+ new StringBuilder(RawHandleWhite(s, style, nfi));
+ RawHandleSign(sb, style, nfi);
+ RawHandleCurrencySymbol(sb, style, nfi);
+ RawHandleDecimalPoint(sb, style, nfi);
+ RawHandleExponent(sb, style, nfi);
+ RawHandleParentheses(sb, style, nfi);
+
+ // Leave this for last, because it needs a fairly
+ // well-formatted input
+ return RawHandleThousands(sb, style, nfi);
+ }
+
+ private static bool StripSign(StringBuilder sb, NumberFormatInfo nfi)
+ {
+ bool isNeg;
+
+ if (sb.ToString().StartsWith(nfi.NegativeSign))
+ {
+ isNeg = true;
+ sb.Remove(0, nfi.NegativeSign.Length);
+ }
+ else if (sb.ToString().EndsWith(nfi.NegativeSign))
+ {
+ isNeg = true;
+ sb.Remove(sb.Length = nfi.NegativeSign.length,
+ nfi.NegativeSign.length);
+ }
+ else if (sb.ToString().StartsWith(nfi.PositiveSign))
+ {
+ isNeg = false;
+ sb.Remove(0, nfi.PositiveSign.Length);
+ }
+ else if (sb.ToString().EndsWith(nfi.PositiveSign))
+ {
+ isNeg = false;
+ sb.Remove(sb.Length = nfi.PositiveSign.length,
+ nfi.PositiveSign.length);
+ }
+ else
+ {
+ isNeg = false;
+ }
+ return isNeg;
+ }
+
+ private static uint EatDigits(StringBuilder sb)
+ {
+ uint work = 0;
+
+ while (sb.Length > 0 && sb[0] >= '0' && sb[0] <= '9')
+ {
+ work *= 10;
+ work += (uint)(sb[0] - '0');
+ sb.Remove(0, 1);
+ }
+ return work;
+ }
+
public static Decimal ParseDecimal(String s, NumberStyles style,
NumberFormatInfo nfi)
{
! // Double does not parse floating point numbers
! if ((style & NumberStyles.AllowHexSpecifier) != 0)
! throw new FormatException(_("Format_HexNotSupported"));
!
! StringBuilder sb = new StringBuilder(RawString(s, style, nfi));
!
! bool negative = StripSign(sb, nfi);
!
! // Parse up to the decimal
! decimal work = (decimal)EatDigits(sb);
!
! // Parse after the decimal
! if (sb.Length > 0
! &&
sb.ToString().StartsWith(nfi.NumberDecimalSeparator))
! {
! uint fracDigits;
! sb.Remove(0, nfi.NumberDecimalSeparator.Length);
! fracDigits = EatDigits(sb);
! if (fracDigits != 0)
! {
! int i;
! int exp = (int)(-Math.Log10(fracDigits))-1;
! if (exp < 0) for (i=0; i<-exp; i++) work /= 10;
! if (exp > 0) for (i=0; i<exp; i++) work *= 10;
! }
! }
!
! // Parse after the exponent
! if (sb.Length > 0 && (sb[0] == 'e' || sb[0] == 'E') )
! {
! uint exp;
! bool negExponent;
! sb.Remove(0, 1);
! if (sb.ToString().StartsWith(nfi.PositiveSign))
! {
! sb.Remove(0, nfi.PositiveSign.Length);
! }
! else if (sb.ToString().StartsWith(nfi.NegativeSign))
! {
! sb.Remove(0, nfi.NegativeSign.Length);
! }
! else
! {
! // Darn it, we're supposed to have a sign.
! throw new
FormatException(_("Format_ExponentRequiresSign"));
! }
! exp= EatDigits(sb);
! if (exp!= 0)
! {
! int i;
! if (exp< 0) for (i=0; i<-exp; i++) work /= 10;
! if (exp> 0) for (i=0; i>exp; i++) work *= 10;
! }
! }
!
! if (sb.Length > 0)
! {
! // Oops. Throw a "junk found" exception.
! throw new FormatException();
! }
!
! if (negative) work *= -1;
!
! return work;
}
***************
*** 698,702 ****
NumberFormatInfo nfi)
{
! return 0.0f;
}
--- 1089,1094 ----
NumberFormatInfo nfi)
{
! // We'll let cast-checking handle overflow exceptions
! return (float)ParseDouble(s, style, nfi);
}
***************
*** 704,708 ****
NumberFormatInfo nfi)
{
! return 0.0d;
}
--- 1096,1159 ----
NumberFormatInfo nfi)
{
! // Double does not parse floating point numbers
! if ((style & NumberStyles.AllowHexSpecifier) != 0)
! throw new FormatException(_("Format_HexNotSupported"));
!
! StringBuilder sb = new StringBuilder(RawString(s, style, nfi));
!
! bool negative = StripSign(sb, nfi);
!
! // Parse up to the decimal
! double work = (double)EatDigits(sb);
!
! // Parse after the decimal
! if (sb.Length > 0
! &&
sb.ToString().StartsWith(nfi.NumberDecimalSeparator))
! {
! uint fracDigits;
! sb.Remove(0, nfi.NumberDecimalSeparator.Length);
! fracDigits = EatDigits(sb);
! if (fracDigits != 0)
! {
! work += (double)fracDigits *
! Math.Pow(10,
-Math.Floor(Math.Log10(fracDigits)) -1) ;
! }
! }
!
! // Parse after the exponent
! if (sb.Length > 0 && (sb[0] == 'e' || sb[0] == 'E') )
! {
! uint exponent;
! bool negExponent;
! sb.Remove(0, 1);
! if (sb.ToString().StartsWith(nfi.PositiveSign))
! {
! sb.Remove(0, nfi.PositiveSign.Length);
! }
! else if (sb.ToString().StartsWith(nfi.NegativeSign))
! {
! sb.Remove(0, nfi.NegativeSign.Length);
! }
! else
! {
! // Darn it, we're supposed to have a sign.
! throw new
FormatException(_("Format_ExponentRequiresSign"));
! }
! exponent = EatDigits(sb);
! if (exponent != 0)
! {
! work *= Math.Pow(10, exponent * (negExponent ?
-1 : 1));
! }
! }
!
! if (sb.Length > 0)
! {
! // Oops. Throw a "junk found" exception.
! throw new FormatException();
! }
!
! if (negative) work *= -1.0d;
!
! return work;
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Dotgnu-pnet-commits] CVS: pnetlib/runtime/System/Private NumberParser.cs,1.3,1.4,
Jonathan Springer <address@hidden> <=