0

This is a C# implementation of a function to determine whether a string represents a valid JSON number. The function is called IsJsonNumber and takes a single parameter, input, which is the string to be tested.

The function first checks if the input string is null or empty, in which case it returns false.This implementation is designed to conform to the JSON specification as from json.org.

using System;

namespace Json
{
    public static class JsonNumber
    {
        public static bool IsJsonNumber(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return false;
            }

            int dotIndex = input.IndexOf('.');
            int exponentIndex = input.IndexOfAny(new[] { 'e', 'E' });

            return IsInteger(Integer(input, dotIndex, exponentIndex))
                && IsFraction(Fraction(input, dotIndex, exponentIndex))
                && IsExponent(Exponent(input, exponentIndex))
                && !input.EndsWith(".");
        }

        private static bool IsDigits(string input)
        {
            foreach (char c in input)
            {
                if (!char.IsDigit(c))
                {
                    return false;
                }
            }

            return input.Length > 0;
        }

        private static string Integer(string input, int dotIndex, int exponentIndex)
        {
            if (dotIndex < 0 && exponentIndex < 0)
            {
                return input;
            }

            int end = dotIndex < 0 ? exponentIndex : dotIndex;
            return input[..end];
        }

        private static bool IsInteger(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return false;
            }

            if (input[0] == '-')
            {
                input = input[1..];
            }

            if (input.Length == 1 && input[0] == '0')
            {
                return true;
            }

            if (input[0] == '0')
            {
                return false;
            }

            return IsDigits(input);
        }

        private static string Fraction(string input, int dotIndex, int exponentIndex)
        {
            if (dotIndex < 0)
            {
                return "";
            }

            int start = dotIndex + 1;
            int end = exponentIndex < 0 ? input.Length : exponentIndex;
            return input[start..end];
        }

        private static bool IsFraction(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return true;
            }

            if (!IsDigits(input))
            {
                return false;
            }

            return (input[0] != '0') || input.TrimEnd('0').Length > 0;
        }

        private static string Exponent(string input, int exponentIndex)
        {
            if (exponentIndex < 0)
            {
                return "";
            }

            int start = exponentIndex + 1;
            return input[start..];
        }

        private static bool IsExponent(string input)
        {
            if (string.IsNullOrEmpty(input))
            {
                return true;
            }

            int signIndex = input.IndexOfAny(new[] { '+', '-' });
            if (signIndex == -1)
            {
                // No sign, just digits
                return IsDigits(input);
            }
            else if (signIndex == input.Length - 1)
            {
                // Sign at the end, not valid
                return false;
            }
            else
            {
                // Sign with digits
                string digits = input[(signIndex + 1) ..];
                return IsDigits(digits) && digits.Length > 0;
            }
        }
    }
}

I have one test that is failing.

 [Fact]
        public void TheExponentIsAlwaysComplete()
        {
            Assert.False(IsJsonNumber("22e"));
            Assert.False(IsJsonNumber("22e+"));
            Assert.False(IsJsonNumber("23E-"));
        }

And if I try to fix it it will make the basic tests (like following) to fail:

  [Fact]
        public void CanBeZero()
        {
            Assert.True(IsJsonNumber("0"));
        }

        
        [Fact]
        public void CanHaveASingleDigit()
        {
            Assert.True(IsJsonNumber("7"));
        }

        [Fact]
        public void CanHaveMultipleDigits()
        {
            Assert.True(IsJsonNumber("70"));
        }
Raluca123
  • 9
  • 4
  • This is a good opportunity for you to start familiarizing yourself with [using a debugger](https://stackoverflow.com/q/25385173/328193). When you step through the code in a debugger, which operation first produces an unexpected result? What were the values used in that operation? What was the result? What result was expected? Why? To learn more about this community and how we can help you, please start with the [tour] and read [ask] and its linked resources. – David Apr 20 '23 at 17:10
  • 1
    What is your question? – Mark Seemann Apr 20 '23 at 17:16
  • Have you tried using a combination of `long.TryParse` and `double.TryParse`? Are there differences between JSON's numbers and C#'s? – Flydog57 Apr 20 '23 at 17:41
  • 1
    @Flydog57 https://www.json.org/json-en.html does not limit size of a "number" - so, while practical, using long/double to parse will miss large portion of *valid* JSON numbers. – Alexei Levenkov Apr 20 '23 at 18:14

0 Answers0