How to find string value is in exponential format in C#?

4.2k views Asked by At

I want to find whether string has exponential format or not. Currently i am checking like below.

var s = "1.23E+04";
var hasExponential = s.Contains("E");

But i know this is not the proper way. So can anyone please guide proper and fastest way to achieve my requirement?

3

There are 3 answers

0
sstan On BEST ANSWER

If you also want to make sure it really is a number, not just a string with an 'E' in it, maybe a function like this can be helpful. The logic remains simple.

private bool IsExponentialFormat(string str)
{
    double dummy;
    return (str.Contains("E") || str.Contains("e")) && double.TryParse(str, out dummy);
}
7
Der Kommissar On

You could always split on e. Or use double.TryParse. Both work pretty well. (I would bet the ParseExponential2 is faster for valid ones, whereas ParseExponential1 could be faster for invalid ones.)

public static void _Main(string[] args)
{
    string[] exponentials = new string[] { "1.23E+4", "1.23E+04", "1.23e+4", "1.23", "1.23e+4e+4", "abce+def", "1.23E-04" };

    for (int i = 0; i < exponentials.Length; i++)
        Console.WriteLine("Input: {0}; Result 1: {1}; Result 2: {2}; Result 3: {3}", exponentials[i], (ParseExponential1(exponentials[i]) ?? 0), (ParseExponential2(exponentials[i]) ?? 0), (ParseExponential3(exponentials[i]) ?? 0));
}

public static double? ParseExponential1(string input)
{
    if (input.Contains("e") || input.Contains("E"))
    {
        string[] inputSplit = input.Split(new char[] { 'e', 'E' });

        if (inputSplit.Length == 2) // If there were not two elements split out, it's an invalid exponential.
        {
            double left = 0;
            int right = 0;

            if (double.TryParse(inputSplit[0], out left) && int.TryParse(inputSplit[1], out right) // Parse the values
                && (left >= -5.0d && left <= 5.0d && right >= -324) // Check that the values are within the range of a double, this is the minimum.
                && (left >= -1.7d && left <= 1.7d && right <= 308)) // Check that the values are within the range of a double, this is the maximum.
            {
                double result = 0;

                if (double.TryParse(input, out result))
                    return result;
            }
        }
    }

    return null;
}

public static double? ParseExponential2(string input)
{
    if (input.Contains("e") || input.Contains("E"))
    {
        double result = 0;

        if (double.TryParse(input, out result))
            return result;
    }

    return null;
}

public static double? ParseExponential3(string input)
{
    double result = 0;

    if (double.TryParse(input, out result))
        return result;

    return null;
}

If the ParseExponential1, ParseExponential2 or ParseExponential3 returns null, then it was invalid. This also allows you to parse it at the same time and get the value indicated.

The only issue with ParseExponential3 is that it will also return valid numbers if they are not exponential. (I.e., for the 1.23 case it will return 1.23.)

You could also remove the checks for the double range. They are just there for completeness.

Also, to prove a point, I just ran a benchmark with the code below, and the Regex option in the other answer by nevermoi took 500ms to run 100,000 times over the exponentials array, the ParseExponential1 option took 547ms, and the ParseExponential2 option 317ms. The method by sstan took 346ms. Lastly, the fastest was my ParseExponential3 method at 134ms.

string[] exponentials = new string[] { "1.23E+4", "1.23E+04", "1.23e+4", "1.23", "1.23e+4e+4", "abce+def", "1.23E-04" };

Stopwatch sw = new Stopwatch();
sw.Start();
for (int round = 0; round < 100000; round++)
    for (int i = 0; i < exponentials.Length; i++)
        ParseExponential1(exponentials[i]);
sw.Stop();
Console.WriteLine("Benchmark 1 (ParseExponential1) complete: {0}ms", sw.ElapsedMilliseconds);

sw.Reset();

sw.Start();
for (int round = 0; round < 100000; round++)
    for (int i = 0; i < exponentials.Length; i++)
        ParseExponential2(exponentials[i]);
sw.Stop();
Console.WriteLine("Benchmark 2 (ParseExponential2) complete: {0}ms", sw.ElapsedMilliseconds);
sw.Reset();
string pattern = @"^\d{1}.\d+(E\+)\d+$";
Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);

sw.Start();
for (int round = 0; round < 100000; round++)
    for (int i = 0; i < exponentials.Length; i++)
        rgx.IsMatch(exponentials[i]);
sw.Stop();
Console.WriteLine("Benchmark 3 (Regex Parse) complete: {0}ms", sw.ElapsedMilliseconds);
sw.Reset();

sw.Start();
for (int round = 0; round < 100000; round++)
    for (int i = 0; i < exponentials.Length; i++)
        IsExponentialFormat(exponentials[i]);
sw.Stop();
Console.WriteLine("Benchmark 4 (IsExponentialFormat) complete: {0}ms", sw.ElapsedMilliseconds);

sw.Start();
for (int round = 0; round < 100000; round++)
    for (int i = 0; i < exponentials.Length; i++)
        ParseExponential3(exponentials[i]);
sw.Stop();
Console.WriteLine("Benchmark 5 (ParseExponential3) complete: {0}ms", sw.ElapsedMilliseconds);

And the following method was added:

private static bool IsExponentialFormat(string str)
{
    double dummy;
    return (str.Contains("E") || str.Contains("e")) && double.TryParse(str, out dummy);
}
6
nevermoi On

Try to use regular expression?

string s = "1.23E+04";
string pattern = @"^\d{1}.\d+(E\+)\d+$";
Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
bool hasExponential = rgx.IsMatch(s);