【问题标题】:How to find string value is in exponential format in C#?如何在 C# 中以指数格式查找字符串值?
【发布时间】:2015-08-27 22:13:54
【问题描述】:

我想查找字符串是否具有指数格式。目前我正在检查如下。

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

但我知道这不是正确的方法。那么任何人都可以指导正确和最快的方法来实现我的要求吗?

【问题讨论】:

  • @GrantWinney,如果它是指数形式,我想使用另一个变量中的另一个值

标签: c# wpf string number-formatting exponential


【解决方案1】:

尝试使用正则表达式?

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

【讨论】:

  • 当我们使用正则表达式时,性能应该会受到影响。那么你能告诉性能有效的方法吗?
  • @Selvamz 性能总是会受到影响,不要拒绝它,因为您认为它可能会影响您的解决方案,但它可能不会。
  • @Bas 这个方法的执行速度是 sstan 的方法的两倍,或者我提到的第二种方法。
  • @EBrown 但与正在运行的任何算法相反,它可能是总运行时间的 0.001 或 0.002
  • @Bas 如果 OP 关心性能,那是一个无关紧要的声明。它是运行时的什么部分并不重要,如果 OP 想要最快的算法,这不是它。
【解决方案2】:

如果您还想确保它确实是一个数字,而不仅仅是一个带有“E”的字符串,那么这样的函数可能会有所帮助。逻辑很简单。

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

【讨论】:

    【解决方案3】:

    你总是可以在e 上分手。或使用double.TryParse。两者都工作得很好。 (我敢打赌,ParseExponential2 对于有效的更快,而ParseExponential1 可能对于无效的更快。)

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

    如果ParseExponential1ParseExponential2ParseExponential3返回null,则无效。这也可以让你同时解析它并获取指示的值。

    ParseExponential3 的唯一问题是,如果它们不是指数的,它也会返回有效数字。 (即,对于1.23 情况,它将返回1.23。)

    您还可以删除对double 范围的检查。它们只是为了完整性。

    另外,为了证明一点,我只是用下面的代码运行了一个基准测试,nevermoi 在另一个答案中的Regex 选项使500msexponentials 数组、@987654337 上运行了 100,000 次@ 选项采用 547ms,而 ParseExponential2 选项采用 317ms。 sstan 的方法采用了346ms。最后,最快的是我的ParseExponential3 方法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);
    

    并添加了以下方法:

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

    【讨论】:

    • e-E- 也是有效的。这就是太聪明而无法获得微秒的麻烦。简单确保正确性,这应该始终是第一要务。
    • @sstan 啊,是的,我忘记了负面因素。我会做出改变的。
    • 另外,您正在通过拆分创建一堆新字符串。正则表达式比这快得多。
    • @Bas 你对它进行了基准测试吗?如果不是,则该声明无效。我刚刚对其进行了基准测试,Regex 选项与字符串选项的速度相同,是非字符串选项的两倍。
    • 试试 RegexOptions.Compiled
    猜你喜欢
    • 1970-01-01
    • 2019-10-15
    • 1970-01-01
    • 2013-02-05
    • 1970-01-01
    • 2020-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多