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);
}