Fastest way to check if string contains only digits

后端 未结 20 824
挽巷
挽巷 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:44

    Probably the fastest way is:

    myString.All(c => char.IsDigit(c))
    

    Note: it will return True in case your string is empty which is incorrect (if you not considering empty as valid number/digit )

    0 讨论(0)
  • 2020-12-04 09:45

    this will work perfectly, there is many other ways but this would work

    bool IsDigitsOnly(string str)
        {
            if (str.Length > 0)//if contains characters
            {
                foreach (char c in str)//assign character to c
                {
                    if (c < '0' || c > '9')//check if its outside digit range
                        return false;
                }
            }else//empty string
            {
                return false;//empty string 
            }
    
            return true;//only digits
        }
    
    0 讨论(0)
  • 2020-12-04 09:47

    The char already has an IsDigit(char c) which does this:

     public static bool IsDigit(char c)
        {
          if (!char.IsLatin1(c))
            return CharUnicodeInfo.GetUnicodeCategory(c) == UnicodeCategory.DecimalDigitNumber;
          if ((int) c >= 48)
            return (int) c <= 57;
          else
            return false;
        }
    

    You can simply do this:

    var theString = "839278";
    bool digitsOnly = theString.All(char.IsDigit);
    
    0 讨论(0)
  • 2020-12-04 09:48

    If you are concerned about performance, use neither int.TryParse nor Regex - write your own (simple) function (DigitsOnly or DigitsOnly2 below, but not DigitsOnly3 - LINQ seems to incur a significant overhead).

    Also, be aware that int.TryParse will fail if the string is too long to "fit" into int.

    This simple benchmark...

    class Program {
    
        static bool DigitsOnly(string s) {
            int len = s.Length;
            for (int i = 0; i < len; ++i) {
                char c = s[i];
                if (c < '0' || c > '9')
                    return false;
            }
            return true;
        }
    
        static bool DigitsOnly2(string s) {
            foreach (char c in s) {
                if (c < '0' || c > '9')
                    return false;
            }
            return true;
        }
    
        static bool DigitsOnly3(string s) {
            return s.All(c => c >= '0' && c <= '9');
        }
    
        static void Main(string[] args) {
    
            const string s1 = "916734184";
            const string s2 = "916734a84";
    
            const int iterations = 1000000;
            var sw = new Stopwatch();
    
            sw.Restart();
            for (int i = 0 ; i < iterations; ++i) {
                bool success = DigitsOnly(s1);
                bool failure = DigitsOnly(s2);
            }
            sw.Stop();
            Console.WriteLine(string.Format("DigitsOnly: {0}", sw.Elapsed));
    
            sw.Restart();
            for (int i = 0; i < iterations; ++i) {
                bool success = DigitsOnly2(s1);
                bool failure = DigitsOnly2(s2);
            }
            sw.Stop();
            Console.WriteLine(string.Format("DigitsOnly2: {0}", sw.Elapsed));
    
            sw.Restart();
            for (int i = 0; i < iterations; ++i) {
                bool success = DigitsOnly3(s1);
                bool failure = DigitsOnly3(s2);
            }
            sw.Stop();
            Console.WriteLine(string.Format("DigitsOnly3: {0}", sw.Elapsed));
    
            sw.Restart();
            for (int i = 0; i < iterations; ++i) {
                int dummy;
                bool success = int.TryParse(s1, out dummy);
                bool failure = int.TryParse(s2, out dummy);
            }
            sw.Stop();
            Console.WriteLine(string.Format("int.TryParse: {0}", sw.Elapsed));
    
            sw.Restart();
            var regex = new Regex("^[0-9]+$", RegexOptions.Compiled);
            for (int i = 0; i < iterations; ++i) {
                bool success = regex.IsMatch(s1);
                bool failure = regex.IsMatch(s2);
            }
            sw.Stop();
            Console.WriteLine(string.Format("Regex.IsMatch: {0}", sw.Elapsed));
    
        }
    
    }
    

    ...produces the following result...

    DigitsOnly: 00:00:00.0346094
    DigitsOnly2: 00:00:00.0365220
    DigitsOnly3: 00:00:00.2669425
    int.TryParse: 00:00:00.3405548
    Regex.IsMatch: 00:00:00.7017648
    
    0 讨论(0)
  • 2020-12-04 09:49

    This should work:

    Regex.IsMatch("124", "^[0-9]+$", RegexOptions.Compiled)
    

    int.Parse or int.TryParse won't always work, because the string might contain more digits that an int can hold.

    If you are going to do this check more than once it is useful to use a compiled regex - it takes more time the first time, but is much faster after that.

    0 讨论(0)
  • 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<string>(); //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
    0 讨论(0)
提交回复
热议问题