Exception ex;
return Parse (value, true, out result, out ex);
}
-
-#if NET_4_0
- [MonoTODO]
+
public static BigInteger Parse (string value, NumberStyles style)
{
- throw new NotImplementedException ();
+ return Parse (value, style, null);
}
- [MonoTODO]
public static BigInteger Parse (string value, IFormatProvider provider)
{
- throw new NotImplementedException ();
+ return Parse (value, NumberStyles.Integer, provider);
}
- [MonoTODO]
public static BigInteger Parse (
string value, NumberStyles style, IFormatProvider provider)
{
- throw new InvalidOperationException ();
+ Exception exc;
+ BigInteger res;
+
+ if (!Parse (value, style, provider, false, out res, out exc))
+ throw exc;
+
+ return res;
}
-
- [MonoTODO]
+
public static bool TryParse (
string value, NumberStyles style, IFormatProvider provider,
out BigInteger result)
{
- throw new NotImplementedException ();
+ Exception exc;
+ if (!Parse (value, style, provider, true, out result, out exc)) {
+ result = Zero;
+ return false;
+ }
+
+ return true;
+ }
+
+ internal static bool Parse (string s, NumberStyles style, IFormatProvider fp, bool tryParse, out BigInteger result, out Exception exc)
+ {
+ result = Zero;
+ exc = null;
+
+ if (s == null) {
+ if (!tryParse)
+ exc = new ArgumentNullException ("s");
+ return false;
+ }
+
+ if (s.Length == 0) {
+ if (!tryParse)
+ exc = GetFormatException ();
+ return false;
+ }
+
+ NumberFormatInfo nfi = null;
+ if (fp != null) {
+ Type typeNFI = typeof(System.Globalization.NumberFormatInfo);
+ nfi = (NumberFormatInfo)fp.GetFormat (typeNFI);
+ }
+ if (nfi == null)
+ nfi = Thread.CurrentThread.CurrentCulture.NumberFormat;
+
+ if (!CheckStyle (style, tryParse, ref exc))
+ return false;
+
+ bool AllowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0;
+ bool AllowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0;
+ bool AllowThousands = (style & NumberStyles.AllowThousands) != 0;
+ bool AllowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0;
+ bool AllowParentheses = (style & NumberStyles.AllowParentheses) != 0;
+ bool AllowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0;
+ bool AllowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0;
+ bool AllowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0;
+ bool AllowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0;
+ bool AllowExponent = (style & NumberStyles.AllowExponent) != 0;
+
+ int pos = 0;
+
+ if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+ return false;
+
+ bool foundOpenParentheses = false;
+ bool negative = false;
+ bool foundSign = false;
+ bool foundCurrency = false;
+
+ // Pre-number stuff
+ if (AllowParentheses && s [pos] == '(') {
+ foundOpenParentheses = true;
+ foundSign = true;
+ negative = true; // MS always make the number negative when there parentheses
+ // even when NumberFormatInfo.NumberNegativePattern != 0!!!
+ pos++;
+ if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+ return false;
+
+ if (s.Substring (pos, nfi.NegativeSign.Length) == nfi.NegativeSign) {
+ if (!tryParse)
+ exc = GetFormatException ();
+ return false;
+ }
+
+ if (s.Substring (pos, nfi.PositiveSign.Length) == nfi.PositiveSign) {
+ if (!tryParse)
+ exc = GetFormatException ();
+ return false;
+ }
+ }
+
+ if (AllowLeadingSign && !foundSign) {
+ // Sign + Currency
+ FindSign (ref pos, s, nfi, ref foundSign, ref negative);
+ if (foundSign) {
+ if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+ return false;
+ if (AllowCurrencySymbol) {
+ FindCurrency (ref pos, s, nfi,
+ ref foundCurrency);
+ if (foundCurrency && AllowLeadingWhite &&
+ !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+ return false;
+ }
+ }
+ }
+
+ if (AllowCurrencySymbol && !foundCurrency) {
+ // Currency + sign
+ FindCurrency (ref pos, s, nfi, ref foundCurrency);
+ if (foundCurrency) {
+ if (AllowLeadingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+ return false;
+ if (foundCurrency) {
+ if (!foundSign && AllowLeadingSign) {
+ FindSign (ref pos, s, nfi, ref foundSign,
+ ref negative);
+ if (foundSign && AllowLeadingWhite &&
+ !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+ return false;
+ }
+ }
+ }
+ }
+
+ BigInteger number = Zero;
+ int nDigits = 0;
+ int decimalPointPos = -1;
+ byte digitValue;
+ char hexDigit;
+ bool firstHexDigit = true;
+
+ // Number stuff
+ while (pos < s.Length) {
+
+ if (!ValidDigit (s [pos], AllowHexSpecifier)) {
+ if (AllowThousands &&
+ (FindOther (ref pos, s, nfi.NumberGroupSeparator)
+ || FindOther (ref pos, s, nfi.CurrencyGroupSeparator)))
+ continue;
+
+ if (AllowDecimalPoint && decimalPointPos < 0 &&
+ (FindOther (ref pos, s, nfi.NumberDecimalSeparator)
+ || FindOther (ref pos, s, nfi.CurrencyDecimalSeparator))) {
+ decimalPointPos = nDigits;
+ continue;
+ }
+
+ break;
+ }
+
+ nDigits++;
+
+ if (AllowHexSpecifier) {
+ hexDigit = s [pos++];
+ if (Char.IsDigit (hexDigit))
+ digitValue = (byte)(hexDigit - '0');
+ else if (Char.IsLower (hexDigit))
+ digitValue = (byte)(hexDigit - 'a' + 10);
+ else
+ digitValue = (byte)(hexDigit - 'A' + 10);
+
+ if (firstHexDigit && (byte)digitValue >= 8)
+ negative = true;
+
+ number = number * 16 + digitValue;
+ firstHexDigit = false;
+ continue;
+ }
+
+ number = number * 10 + (byte)(s [pos++] - '0');
+ }
+
+ // Post number stuff
+ if (nDigits == 0) {
+ if (!tryParse)
+ exc = GetFormatException ();
+ return false;
+ }
+
+ //signed hex value
+ if (AllowHexSpecifier && negative) {
+ //number = 123456;
+ BigInteger mask = BigInteger.Pow(16, nDigits) - 1;
+ number = (number ^ mask) + 1;
+ }
+
+ int exponent = 0;
+ if (AllowExponent)
+ if (FindExponent (ref pos, s, ref exponent, tryParse, ref exc) && exc != null)
+ return false;
+
+ if (AllowTrailingSign && !foundSign) {
+ // Sign + Currency
+ FindSign (ref pos, s, nfi, ref foundSign, ref negative);
+ if (foundSign && pos < s.Length) {
+ if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+ return false;
+ }
+ }
+
+ if (AllowCurrencySymbol && !foundCurrency) {
+ if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
+ return false;
+
+ // Currency + sign
+ FindCurrency (ref pos, s, nfi, ref foundCurrency);
+ if (foundCurrency && pos < s.Length) {
+ if (AllowTrailingWhite && !JumpOverWhite (ref pos, s, true, tryParse, ref exc))
+ return false;
+ if (!foundSign && AllowTrailingSign)
+ FindSign (ref pos, s, nfi, ref foundSign,
+ ref negative);
+ }
+ }
+
+ if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
+ return false;
+
+ if (foundOpenParentheses) {
+ if (pos >= s.Length || s [pos++] != ')') {
+ if (!tryParse)
+ exc = GetFormatException ();
+ return false;
+ }
+ if (AllowTrailingWhite && pos < s.Length && !JumpOverWhite (ref pos, s, false, tryParse, ref exc))
+ return false;
+ }
+
+ if (pos < s.Length && s [pos] != '\u0000') {
+ if (!tryParse)
+ exc = GetFormatException ();
+ return false;
+ }
+
+ if (decimalPointPos >= 0)
+ exponent = exponent - nDigits + decimalPointPos;
+
+ if (exponent < 0) {
+ //
+ // Any non-zero values after decimal point are not allowed
+ //
+ BigInteger remainder;
+ number = BigInteger.DivRem(number, BigInteger.Pow(10, -exponent), out remainder);
+
+ if (!remainder.IsZero) {
+ if (!tryParse)
+ exc = new OverflowException ("Value too large or too small. exp="+exponent+" rem = " + remainder + " pow = " + BigInteger.Pow(10, -exponent));
+ return false;
+ }
+ } else if (exponent > 0) {
+ number = BigInteger.Pow(10, exponent) * number;
+ }
+
+ if (number.sign == 0)
+ result = number;
+ else if (negative)
+ result = new BigInteger (-1, number.data);
+ else
+ result = new BigInteger (1, number.data);
+
+ return true;
+ }
+
+ internal static bool CheckStyle (NumberStyles style, bool tryParse, ref Exception exc)
+ {
+ if ((style & NumberStyles.AllowHexSpecifier) != 0) {
+ NumberStyles ne = style ^ NumberStyles.AllowHexSpecifier;
+ if ((ne & NumberStyles.AllowLeadingWhite) != 0)
+ ne ^= NumberStyles.AllowLeadingWhite;
+ if ((ne & NumberStyles.AllowTrailingWhite) != 0)
+ ne ^= NumberStyles.AllowTrailingWhite;
+ if (ne != 0) {
+ if (!tryParse)
+ exc = new ArgumentException (
+ "With AllowHexSpecifier only " +
+ "AllowLeadingWhite and AllowTrailingWhite " +
+ "are permitted.");
+ return false;
+ }
+ } else if ((uint) style > (uint) NumberStyles.Any){
+ if (!tryParse)
+ exc = new ArgumentException ("Not a valid number style");
+ return false;
+ }
+
+ return true;
}
-#endif
+ internal static bool JumpOverWhite (ref int pos, string s, bool reportError, bool tryParse, ref Exception exc)
+ {
+ while (pos < s.Length && Char.IsWhiteSpace (s [pos]))
+ pos++;
+
+ if (reportError && pos >= s.Length) {
+ if (!tryParse)
+ exc = GetFormatException ();
+ return false;
+ }
+
+ return true;
+ }
+
+ internal static void FindSign (ref int pos, string s, NumberFormatInfo nfi,
+ ref bool foundSign, ref bool negative)
+ {
+ if ((pos + nfi.NegativeSign.Length) <= s.Length &&
+ string.CompareOrdinal(s, pos, nfi.NegativeSign, 0, nfi.NegativeSign.Length) == 0) {
+ negative = true;
+ foundSign = true;
+ pos += nfi.NegativeSign.Length;
+ } else if ((pos + nfi.PositiveSign.Length) <= s.Length &&
+ string.CompareOrdinal(s, pos, nfi.PositiveSign, 0, nfi.PositiveSign.Length) == 0) {
+ negative = false;
+ pos += nfi.PositiveSign.Length;
+ foundSign = true;
+ }
+ }
+
+ internal static void FindCurrency (ref int pos,
+ string s,
+ NumberFormatInfo nfi,
+ ref bool foundCurrency)
+ {
+ if ((pos + nfi.CurrencySymbol.Length) <= s.Length &&
+ s.Substring (pos, nfi.CurrencySymbol.Length) == nfi.CurrencySymbol) {
+ foundCurrency = true;
+ pos += nfi.CurrencySymbol.Length;
+ }
+ }
+
+ internal static bool FindExponent (ref int pos, string s, ref int exponent, bool tryParse, ref Exception exc)
+ {
+ exponent = 0;
+
+ if (pos >= s.Length || (s [pos] != 'e' && s[pos] != 'E')) {
+ exc = null;
+ return false;
+ }
+
+ var i = pos + 1;
+ if (i == s.Length) {
+ exc = tryParse ? null : GetFormatException ();
+ return true;
+ }
+
+ bool negative = false;
+ if (s [i] == '-') {
+ negative = true;
+ if(++i == s.Length){
+ exc = tryParse ? null : GetFormatException ();
+ return true;
+ }
+ }
+
+ if (s [i] == '+' && ++i == s.Length) {
+ exc = tryParse ? null : GetFormatException ();
+ return true;
+ }
+
+ long exp = 0; // temp long value
+ for (; i < s.Length; i++) {
+ if (!Char.IsDigit (s [i])) {
+ exc = tryParse ? null : GetFormatException ();
+ return true;
+ }
+
+ // Reduce the risk of throwing an overflow exc
+ exp = checked (exp * 10 - (int) (s [i] - '0'));
+ if (exp < Int32.MinValue || exp > Int32.MaxValue) {
+ exc = tryParse ? null : new OverflowException ("Value too large or too small.");
+ return true;
+ }
+ }
+
+ // exp value saved as negative
+ if(!negative)
+ exp = -exp;
+
+ exc = null;
+ exponent = (int)exp;
+ pos = i;
+ return true;
+ }
+
+ internal static bool FindOther (ref int pos, string s, string other)
+ {
+ if ((pos + other.Length) <= s.Length &&
+ s.Substring (pos, other.Length) == other) {
+ pos += other.Length;
+ return true;
+ }
+
+ return false;
+ }
+
+ internal static bool ValidDigit (char e, bool allowHex)
+ {
+ if (allowHex)
+ return Char.IsDigit (e) || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');
+
+ return Char.IsDigit (e);
+ }
static Exception GetFormatException ()
{
huge_add
};
+ private NumberFormatInfo Nfi = NumberFormatInfo.InvariantInfo;
+ private NumberFormatInfo NfiUser;
+
+ [TestFixtureSetUp]
+ public void SetUpFixture()
+ {
+ NfiUser = new NumberFormatInfo ();
+ NfiUser.CurrencyDecimalDigits = 3;
+ NfiUser.CurrencyDecimalSeparator = ":";
+ NfiUser.CurrencyGroupSeparator = "/";
+ NfiUser.CurrencyGroupSizes = new int[] { 2, 1, 0 };
+ NfiUser.CurrencyNegativePattern = 10; // n $-
+ NfiUser.CurrencyPositivePattern = 3; // n $
+ NfiUser.CurrencySymbol = "XYZ";
+ NfiUser.PercentDecimalDigits = 1;
+ NfiUser.PercentDecimalSeparator = ";";
+ NfiUser.PercentGroupSeparator = "~";
+ NfiUser.PercentGroupSizes = new int[] { 1 };
+ NfiUser.PercentNegativePattern = 2;
+ NfiUser.PercentPositivePattern = 2;
+ NfiUser.PercentSymbol = "%%%";
+ }
+
[Test]
public void Mul () {
long[] values = new long [] { -1000000000L, -1000, -1, 0, 1, 1000, 100000000L };
Assert.AreEqual (10, (int)BigInteger.Parse("+10"), "#7");
Assert.AreEqual (10, (int)BigInteger.Parse("10 "), "#8");
Assert.AreEqual (-10, (int)BigInteger.Parse("-10 "), "#9");
+ Assert.AreEqual (10, (int)BigInteger.Parse(" 10 "), "#10");
+ Assert.AreEqual (-10, (int)BigInteger.Parse(" -10 "), "#11");
+
+ Assert.AreEqual (-1, (int)BigInteger.Parse("F", NumberStyles.AllowHexSpecifier), "#12");
+ Assert.AreEqual (-8, (int)BigInteger.Parse("8", NumberStyles.AllowHexSpecifier), "#13");
+ Assert.AreEqual (8, (int)BigInteger.Parse("08", NumberStyles.AllowHexSpecifier), "#14");
+ Assert.AreEqual (15, (int)BigInteger.Parse("0F", NumberStyles.AllowHexSpecifier), "#15");
+ Assert.AreEqual (-1, (int)BigInteger.Parse("FF", NumberStyles.AllowHexSpecifier), "#16");
+ Assert.AreEqual (255, (int)BigInteger.Parse("0FF", NumberStyles.AllowHexSpecifier), "#17");
+
+ Assert.AreEqual (-17, (int)BigInteger.Parse(" (17) ", NumberStyles.AllowParentheses | NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite), "#18");
+ Assert.AreEqual (-23, (int)BigInteger.Parse(" -23 ", NumberStyles.AllowLeadingSign | NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite), "#19");
+
+ Assert.AreEqual (300000, (int)BigInteger.Parse("3E5", NumberStyles.AllowExponent), "#20");
+ Assert.AreEqual (250, (int)BigInteger.Parse("2"+Nfi.NumberDecimalSeparator+"5E2", NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint), "#21");//2.5E2 = 250
+ Assert.AreEqual (25, (int)BigInteger.Parse("2500E-2", NumberStyles.AllowExponent), "#22");
+
+ Assert.AreEqual ("136236974127783066520110477975349088954559032721408", BigInteger.Parse("136236974127783066520110477975349088954559032721408", NumberStyles.None).ToString(), "#23");
+ Assert.AreEqual ("136236974127783066520110477975349088954559032721408", BigInteger.Parse("136236974127783066520110477975349088954559032721408").ToString(), "#24");
+
+ try {
+ BigInteger.Parse ("2E3.0", NumberStyles.AllowExponent); // decimal notation for the exponent
+ Assert.Fail ("#25");
+ } catch (FormatException) {
+ }
+
+ try {
+ Int32.Parse ("2.09E1", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent);
+ Assert.Fail ("#26");
+ } catch (OverflowException) {
+ }
}
[Test]
Assert.IsTrue (BigInteger.TryParse ("-010", out x), "#11");
Assert.AreEqual (-10, (int)x, "#12");
+
+ //Number style and format provider
+
+ Assert.IsFalse (BigInteger.TryParse ("null", NumberStyles.None, null, out x), "#13");
+ Assert.AreEqual (0, (int)x, "#14");
+ Assert.IsFalse (BigInteger.TryParse ("-10", NumberStyles.None, null, out x), "#15");
+ Assert.IsFalse (BigInteger.TryParse ("(10)", NumberStyles.None, null, out x), "#16");
+ Assert.IsFalse (BigInteger.TryParse (" 10", NumberStyles.None, null, out x), "#17");
+ Assert.IsFalse (BigInteger.TryParse ("10 ", NumberStyles.None, null, out x), "#18");
+
+ Assert.IsTrue (BigInteger.TryParse ("-10", NumberStyles.AllowLeadingSign, null, out x), "#19");
+ Assert.AreEqual (-10, (int)x, "#20");
+ Assert.IsTrue (BigInteger.TryParse ("(10)", NumberStyles.AllowParentheses, null, out x), "#21");
+ Assert.AreEqual (-10, (int)x, "#22");
+ Assert.IsTrue (BigInteger.TryParse (" 10", NumberStyles.AllowLeadingWhite, null, out x), "#23");
+ Assert.AreEqual (10, (int)x, "#24");
+ Assert.IsTrue (BigInteger.TryParse ("10 ", NumberStyles.AllowTrailingWhite, null, out x), "#25");
+ Assert.AreEqual (10, (int)x, "#26");
+
+ Assert.IsFalse (BigInteger.TryParse ("$10", NumberStyles.None, null, out x), "#26");
+ Assert.IsFalse (BigInteger.TryParse ("$10", NumberStyles.None, Nfi, out x), "#27");
+ Assert.IsFalse (BigInteger.TryParse ("%10", NumberStyles.None, Nfi, out x), "#28");
+ Assert.IsFalse (BigInteger.TryParse ("10 ", NumberStyles.None, null, out x), "#29");
+
+ Assert.IsTrue (BigInteger.TryParse ("10", NumberStyles.None, null, out x), "#30");
+ Assert.AreEqual (10, (int)x, "#31");
+ Assert.IsTrue (BigInteger.TryParse (Nfi.CurrencySymbol + "10", NumberStyles.AllowCurrencySymbol, Nfi, out x), "#32");
+ Assert.AreEqual (10, (int)x, "#33");
+ Assert.IsFalse (BigInteger.TryParse ("%10", NumberStyles.AllowCurrencySymbol, Nfi, out x), "#34");
+ }
+
+ [Test]
+ public void TestUserCurrency ()
+ {
+ const int val1 = -1234567;
+ const int val2 = 1234567;
+
+ string s = "";
+ BigInteger v;
+ s = val1.ToString ("c", NfiUser);
+ Assert.AreEqual ("1234/5/67:000 XYZ-", s, "Currency value type 1 is not what we want to try to parse");
+ v = BigInteger.Parse ("1234/5/67:000 XYZ-", NumberStyles.Currency, NfiUser);
+ Assert.AreEqual (val1, (int)v);
+
+ s = val2.ToString ("c", NfiUser);
+ Assert.AreEqual ("1234/5/67:000 XYZ", s, "Currency value type 2 is not what we want to try to parse");
+ v = BigInteger.Parse (s, NumberStyles.Currency, NfiUser);
+ Assert.AreEqual (val2, (int)v);
}
[Test]