一般來說,在C#中若我們想要判斷字串是否為數值形式。多半我們會利用TryParse、正規表示式這兩種方式來做處理。相關的文章在網路上已經很多了,像是TryParse的方法就可以參閱HOW TO:判斷字串是否表示數值 (C# 程式設計手冊)這篇MSDN文章。

這邊摘錄MSDN的範例,簡單的帶過:    
int i = 0; string s = “108”; bool result = int.TryParse(s, out i); //i now = 108

以上就是判斷字串是否為數值的程式寫法,相信這個簡單的程式大家應該都會寫,這邊就不再深入探討。今天要談的重點是當今天碰到要判斷很多字串是否都為數值時,您會怎摸樣去做?

這邊我大概的提出了幾個我能想到的作法,再對其效能做些比較。

方法一

應該是大家最常用的方法,分別判斷所有的字串是否為數值。 

      static Boolean IsNumeric1(string[] values)
    {
        int tempValue;
        foreach (string value in values)
        {
            if (!int.TryParse(value, out tempValue))
                return false;
        }
        return true;
    }

方法二

主要是把所有字串先合併成一個字串,再用TryParse作數值判斷的動作。(這個方法需特別注意的是,此種合併的作法可能會讓數值溢位。) 

方法二之一

不處理負數的情況 

      static Boolean IsNumeric2_1(string[] values)
    {
        int tempValue;
        return int.TryParse(string.Join(string.Empty, values), out tempValue);
    }

方法二之二

處理負數的情況 

      static Boolean IsNumeric2_2(string[] values)
    {
        int tempValue;
        int idx = 0;
        foreach (string value in values)
        {
            values[idx] = value.TrimStart('-');
        }
        return int.TryParse(string.Join(string.Empty, values), out tempValue);
    }

方法三

用正規表示式分別判斷其是否為數值。 

      static Boolean IsNumeric3(string[] values)
    {
        foreach (string value in values)
        {
            if (!Regex.IsMatch(value,@"\d+"))
                return false;
        }
        return true;
    }

方法四

把所有字串先合併成一個字串,再用正規表示式作數值判斷的動作。  

      static Boolean IsNumeric4(string[] values)
    {
        return Regex.IsMatch(string.Join(string.Empty, values), @"\d+");
    }

效能比較

測試程式如下:    

      static void Main(string[] args)
    {
        //String[] values = InitTestStrings(1);
        String[] values = InitTestStrings(10);
        //String[] values = InitTestStrings(10,1);
        //String[] values = InitTestStrings(10, 2);
        //String[] values = InitTestStrings(10, 3);
        int testCount = 1000000;
        Stopwatch sw = Stopwatch.StartNew();
        for (int idx = 0; idx < testCount; ++idx)
        {
            IsNumeric1(values);
        }
        sw.Stop();
        Console.WriteLine("Method1: " + sw.ElapsedMilliseconds + " ms");

        sw.Reset();
        sw.Start();
        for (int idx = 0; idx < testCount; ++idx)
        {
            IsNumeric2_1(values);
        }
        sw.Stop();
        Console.WriteLine("Method2-1: " + sw.ElapsedMilliseconds + " ms");

        sw.Reset();
        sw.Start();
        for (int idx = 0; idx < testCount; ++idx)
        {
            IsNumeric2_2(values);
        }
        sw.Stop();
        Console.WriteLine("Method2-2: " + sw.ElapsedMilliseconds + " ms");

        sw.Reset();
        sw.Start();
        for (int idx = 0; idx < testCount; ++idx)
        {
            IsNumeric3(values);
        }
        sw.Stop();
        Console.WriteLine("Method3: " + sw.ElapsedMilliseconds + " ms");

        sw.Reset();
        sw.Start();
        for (int idx = 0; idx < testCount; ++idx)
        {
            IsNumeric4(values);
        }
        sw.Stop();
        Console.WriteLine("Method4: " + sw.ElapsedMilliseconds + " ms");
    }

    static string[] InitTestStrings(int count)
    {
        string[] testStrings = new string[count];
        for (int idx = 0; idx < count; ++idx)
        {
            testStrings[idx] = idx.ToString();
        }
        return testStrings;
    }

    static string[] InitTestStrings(int count,int nonValueIndex)
    {
        string[] testStrings = InitTestStrings(count);
        testStrings[nonValueIndex] = "Test";
        return testStrings;
    }

帶入以下測試條件 : 

String[] values = InitTestStrings(1);

其運行結果如下:

帶入以下測試條件 : 

          String[] values = InitTestStrings(10);

其運行結果如下:

帶入以下測試條件 : 

String[] values = InitTestStrings(10,1);

其運行結果如下:

帶入以下測試條件 : 

          String[] values = InitTestStrings(10, 2);

其運行結果如下:

帶入以下測試條件 : 

String[] values = InitTestStrings(10, 3);

其運行結果如下:

帶入以下測試條件 :

String[] values = InitTestStrings(10, 4);

其運行結果如下:

由以上實驗,我們可以看見的是,在某些條件下,方法二這種先合併字串,再用TryParse的方式效能最佳。某些條件下,先合併字串在集中判斷可以獲得較好的效能。主要取決於字串合併數量的多寡、與第幾個字串不為數值這兩個條件。

實驗下來我們也可以發現,字串處理的OverHead好像比數值判斷來得低很多。因此使用字串合併後再判斷約有7/10的機率可獲取較高的效,另外適時的使用功能不那摸強大的判斷方式,也可以適當的提升效能,而使用正規表示式的方式則是效能最差的判斷方式。

另外一提,有興趣的可以試者把Int.TryParse改為Decimal.TryParse看看,其對效能也有相當的影響,所以依需求用對適當的型別來處理也是很重要的。

Int32.TryParse 方法

HOW TO:判斷字串是否表示數值 (C# 程式設計手冊)