/// <inheritdoc cref="TryParseInt(string, ref int, out int, int, bool)"/> public static bool TryParseInt(ref UString input, out long result, int radix = 10, ParseFlag flags = 0) { if ((flags & ParseFlag.SkipSpacesInFront) != 0) { input = SkipSpaces(input); } UString s = input; bool negative = false; char c = s[0, '\0']; if (c == '-' || c == '+') { negative = c == '-'; s = s.Slice(1); } ulong resultU = 0; int numDigits; bool ok = TryParseUInt(ref s, ref resultU, radix, flags, out numDigits); result = negative ? -(long)resultU : (long)resultU; if (numDigits != 0) { input = s; } return(ok && ((result < 0) == negative || result == 0)); }
/// <summary>Returns a string with any spaces and tabs removed from the beginning.</summary> public static UString SkipSpaces(UString s) { char c; while ((c = s[0, '\0']) == ' ' || c == '\t') { s = s.Slice(1); } return(s); }
static bool TryParseUInt(ref UString s, ref ulong result, int radix, ParseFlag flags, out int numDigits) { numDigits = 0; if ((flags & ParseFlag.SkipSpacesInFront) != 0) { s = SkipSpaces(s); } bool overflow = false; int oldStart = s.InternalStart; for (;; s = s.Slice(1)) { char c = s[0, '\0']; uint digit = (uint)Base36DigitValue(c); if (digit >= radix) { if ((c == ' ' || c == '\t') && (flags & ParseFlag.SkipSpacesInsideNumber) != 0) { continue; } else if (c == '_' && (flags & ParseFlag.SkipUnderscores) != 0) { continue; } else { break; } } ulong next; try { next = checked (result * (uint)radix + digit); } catch (OverflowException) { overflow = true; if ((flags & ParseFlag.StopBeforeOverflow) != 0) { return(false); } next = result * (uint)radix + digit; } numDigits++; result = next; } return(!overflow && numDigits > 0); }
public static int TryParseHex(ref UString s, out int value) { value = 0; int len = 0; for (;; len++, s = s.Slice(1)) { int digit = HexDigitValue(s[0, '\0']); if (digit == -1) { return(len); } else { value = value * 16 + digit; } } }
private static int SkipExtraDigits(ref UString s, int radix, ParseFlag flags) { for (int skipped = 0;; skipped++, s = s.Slice(1)) { char c = s[0, '\0']; uint digit = (uint)Base36DigitValue(c); if (digit >= radix) { if ((c == ' ' || c == '\t') && (flags & ParseFlag.SkipSpacesInsideNumber) != 0) { continue; } else if (c == '_' && (flags & ParseFlag.SkipUnderscores) != 0) { continue; } else { return(skipped); } } } }
/// <summary>Low-level method that identifies the parts of a float literal /// of arbitrary base (typically base 2, 10, or 16) with no prefix or /// suffix, such as <c>2.Cp0</c> (which means 2.75 in base 16).</summary> /// <param name="radix">Base of the number to parse; must be between 2 /// and 36.</param> /// <param name="mantissa">Integer magnitude of the number.</param> /// <param name="exponentBase2">Base-2 exponent to apply, as specified by /// the 'p' suffix, or 0 if there is no 'p' suffix..</param> /// <param name="exponentBase10">Base-10 exponent to apply, as specified by /// the 'e' suffix, or 0 if there is no 'e' suffix..</param> /// <param name="exponentBaseR">Base-radix exponent to apply. This number /// is based on the front part of the number only (not including the 'p' or /// 'e' suffix). Negative values represent digits after the decimal point, /// while positive numbers represent 64-bit overflow. For example, if the /// input is <c>12.3456</c> with <c>radix=10</c>, the output will be /// <c>mantissa=123456</c> and <c>exponentBaseR=-4</c>. If the input is /// <c>0123_4567_89AB_CDEF_1234.5678</c> with <c>radix=16</c>, the mantissa /// overflows, and the result is <c>mantissa = 0x1234_5678_9ABC_DEF1</c> /// with <c>exponentBaseR=3</c>.</param> /// <param name="numDigits">Set to the number of digits in the number, not /// including the exponent part.</param> /// <param name="flags">Alters parsing behavior, see <see cref="ParseFlags"/>.</param> /// <remarks> /// The syntax required is /// <code> /// ( '+'|'-' )? /// ( Digits ('.' Digits?)? | '.' Digits ) /// ( ('p'|'P') ('-'|'+')? DecimalDigits+ )? /// ( ('e'|'E') ('-'|'+')? DecimalDigits+ )? /// </code> /// where Digits refers to one digits in the requested base, possibly /// including underscores or spaces if the flags allow it; similarly, /// DecimalDigits refers to base-10 digits and is also affected by the /// flags. /// <para/> /// Returns false if there was an error interpreting the input. /// <para/> /// To keep the parser relatively simple, it does not roll back in case of /// error the way the int parser does. For example, given the input "23p", /// the 'p' is consumed and causes the method to return false, even though /// the parse could have been successful if it had ignored the 'p'. /// </remarks> public static bool TryParseFloatParts(ref UString source, int radix, out bool negative, out ulong mantissa, out int exponentBaseR, out int exponentBase2, out int exponentBase10, out int numDigits, ParseFlag flags = 0) { flags |= G.ParseFlag.StopBeforeOverflow; if ((flags & ParseFlag.SkipSpacesInFront) != 0) { source = SkipSpaces(source); } negative = false; char c = source[0, '\0']; if (c == '-' || c == '+') { negative = c == '-'; source = source.Slice(1); } int numDigits2 = 0; mantissa = 0; exponentBase2 = 0; exponentBase10 = 0; exponentBaseR = 0; bool success = TryParseUInt(ref source, ref mantissa, radix, flags, out numDigits); if (!success) // possible overflow, extra digits remain if so { numDigits += (exponentBaseR = SkipExtraDigits(ref source, radix, flags)); } c = source[0, '\0']; if (c == '.' || (c == ',' && (flags & ParseFlag.AllowCommaDecimalPoint) != 0)) { source = source.Slice(1); if (exponentBaseR == 0) { success = TryParseUInt(ref source, ref mantissa, radix, flags, out numDigits2); if ((numDigits += numDigits2) == 0) { return(false); } exponentBaseR = -numDigits2; } else { Debug.Assert(!success); } if (!success) // possible overflow, extra digits remain if so { numDigits += SkipExtraDigits(ref source, radix, flags); } c = source[0, '\0']; } if (numDigits == 0) { return(false); } success = true; if (c == 'p' || c == 'P') { source = source.Slice(1); success = TryParseInt(ref source, out exponentBase2, 10, flags) && success; c = source[0, '\0']; } if (c == 'e' || c == 'E') { source = source.Slice(1); success = TryParseInt(ref source, out exponentBase10, 10, flags) && success; } return(success); }