Fastest way to check if string contains only digits

后端 未结 20 878
挽巷
挽巷 2020-12-04 09:07

I know a few ways how to check this. regex,int.parse,tryparse,looping.

can anyone tell me what is the fastest way to check?

the nee

20条回答
  •  孤城傲影
    2020-12-04 09:51

    Can be about 20% faster by using just one comparison per char and for instead of foreach:

    bool isDigits(string s) 
    { 
        if (s == null || s == "") return false; 
    
        for (int i = 0; i < s.Length; i++) 
            if ((s[i] ^ '0') > 9) 
                return false; 
    
        return true; 
    }
    

    Code used for testing (always profile because the results depend on hardware, versions, order, etc.):

    static bool isDigitsFr(string s) { if (s == null || s == "") return false; for (int i = 0; i < s.Length; i++) if (s[i] < '0' || s[i] > '9') return false; return true; }
    static bool isDigitsFu(string s) { if (s == null || s == "") return false; for (int i = 0; i < s.Length; i++) if ((uint)(s[i] - '0') > 9) return false; return true; }
    static bool isDigitsFx(string s) { if (s == null || s == "") return false; for (int i = 0; i < s.Length; i++) if ((s[i] ^ '0') > 9) return false; return true; }
    static bool isDigitsEr(string s) { if (s == null || s == "") return false; foreach (char c in s) if (c < '0' || c > '9') return false; return true; }
    static bool isDigitsEu(string s) { if (s == null || s == "") return false; foreach (char c in s) if ((uint)(c - '0') > 9) return false; return true; }
    static bool isDigitsEx(string s) { if (s == null || s == "") return false; foreach (char c in s) if ((c ^ '0') > 9) return false; return true; }
    static void test()
    {
        var w = new Stopwatch(); bool b; var s = int.MaxValue + ""; int r = 12345678*2; var ss = new SortedSet(); //s = string.Concat(Enumerable.Range(0, 127).Select(i => ((char)i ^ '0') < 10 ? 1 : 0));
        w.Restart(); for (int i = 0; i < r; i++) b = s.All(char.IsDigit); w.Stop(); ss.Add(w.Elapsed + ".All .IsDigit"); 
        w.Restart(); for (int i = 0; i < r; i++) b = s.All(c => c >= '0' && c <= '9'); w.Stop(); ss.Add(w.Elapsed + ".All <>"); 
        w.Restart(); for (int i = 0; i < r; i++) b = s.All(c => (c ^ '0') < 10); w.Stop(); ss.Add(w.Elapsed + " .All ^"); 
        w.Restart(); for (int i = 0; i < r; i++) b = isDigitsFr(s); w.Stop(); ss.Add(w.Elapsed + " for     <>");
        w.Restart(); for (int i = 0; i < r; i++) b = isDigitsFu(s); w.Stop(); ss.Add(w.Elapsed + " for     -");
        w.Restart(); for (int i = 0; i < r; i++) b = isDigitsFx(s); w.Stop(); ss.Add(w.Elapsed + " for     ^");
        w.Restart(); for (int i = 0; i < r; i++) b = isDigitsEr(s); w.Stop(); ss.Add(w.Elapsed + " foreach <>");
        w.Restart(); for (int i = 0; i < r; i++) b = isDigitsEu(s); w.Stop(); ss.Add(w.Elapsed + " foreach -");
        w.Restart(); for (int i = 0; i < r; i++) b = isDigitsEx(s); w.Stop(); ss.Add(w.Elapsed + " foreach ^");
        MessageBox.Show(string.Join("\n", ss)); return;
    }
    

    Results on Intel i5-3470 @ 3.2GHz, VS 2015 .NET 4.6.1 Release mode and optimizations enabled:

    time    method          ratio
    0.7776  for     ^       1.0000 
    0.7984  foreach -       1.0268 
    0.8066  foreach ^       1.0372 
    0.8940  for     -       1.1497 
    0.8976  for     <>      1.1543 
    0.9456  foreach <>      1.2160 
    4.4559  .All <>         5.7303 
    4.7791  .All ^          6.1458 
    4.8539  .All. IsDigit   6.2421 
    

    For anyone tempted to use the shorter methods, note that

    • .All results in true for empty strings and exception for null strings
    • char.IsDigit is true for all Unicode characters in the Nd category
    • int.TryParse also allows white spase and sign characters

提交回复
热议问题