Last active
January 7, 2026 11:28
-
-
Save RichardD2/ee6c02a4386812d882ec630b6d1a3472 to your computer and use it in GitHub Desktop.
Simple integer parsing from a ReadOnlySpan<char>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Globalization; | |
| using System.Runtime.CompilerServices; | |
| internal static class Number | |
| { | |
| #if NET8_0_OR_GREATER | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| internal static bool TryParseInt32(ReadOnlySpan<char> input, out int value) => int.TryParse(input, out value); | |
| #else | |
| internal static bool TryParseInt32(ReadOnlySpan<char> input, out int value) | |
| { | |
| // Ignore all leading and trailing white-space: | |
| input = input.Trim(); | |
| if (input.IsEmpty) | |
| { | |
| value = 0; | |
| return false; | |
| } | |
| // Check for a leading sign (+/-): | |
| NumberFormatInfo format = NumberFormatInfo.CurrentInfo; | |
| int sign = ExtractSign(ref input, format); | |
| // Check that we have something other than the sign: | |
| if (input.IsEmpty) | |
| { | |
| value = 0; | |
| return false; | |
| } | |
| const uint Limit = int.MaxValue / 10; // Once we exceed this value, we cannot add another digit. | |
| const uint PositiveLimit = (uint)int.MaxValue; // Maximum absolute value for positive integers. | |
| const uint NegativeLimit = PositiveLimit + 1; // Maximum absolute value for negative integers. | |
| uint result = 0; | |
| foreach (char c in input) | |
| { | |
| // If it's not a valid digit, or we've already exceeded the limit, we cannot add another digit: | |
| if (c < '0' || c > '9' || result > Limit) | |
| { | |
| value = 0; | |
| return false; | |
| } | |
| result *= 10; | |
| result += (uint)(c - '0'); | |
| // For positive values, verify that the result is not greater than int.MaxValue [2147483647]; | |
| // For negative values, verify that the result is not greater than Abs(int.MinValue) [2147483648]: | |
| if (result > PositiveLimit) | |
| { | |
| if (sign == 1 || result > NegativeLimit) | |
| { | |
| value = 0; | |
| return false; | |
| } | |
| } | |
| } | |
| value = sign * (int)result; | |
| return true; | |
| } | |
| private static int ExtractSign(ref ReadOnlySpan<char> input, NumberFormatInfo format) | |
| { | |
| if (!string.IsNullOrEmpty(format.NegativeSign)) | |
| { | |
| if (format.NegativeSign.Length == 1) | |
| { | |
| if (input[0] == format.NegativeSign[0]) | |
| { | |
| input = input.Slice(1); | |
| return -1; // Negative | |
| } | |
| } | |
| else | |
| { | |
| if (input.StartsWith(format.NegativeSign)) | |
| { | |
| input = input.Slice(format.NegativeSign.Length); | |
| return -1; // Negative | |
| } | |
| } | |
| } | |
| if (!string.IsNullOrEmpty(format.PositiveSign)) | |
| { | |
| if (format.PositiveSign.Length == 1) | |
| { | |
| if (input[0] == format.PositiveSign[0]) | |
| { | |
| input = input.Slice(1); | |
| } | |
| } | |
| else | |
| { | |
| if (input.StartsWith(format.PositiveSign)) | |
| { | |
| input = input.Slice(format.PositiveSign.Length); | |
| } | |
| } | |
| } | |
| return 1; // Positive | |
| } | |
| #endif | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment