Fastest way to check if string contains only digits in C#

C#StringPerformance

C# Problem Overview


I know a few ways of how to check if a string contains only digits:
RegEx, int.parse, tryparse, looping, etc.

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

I need only to CHECK the value, no need to actually parse it.

By "digit" I mean specifically ASCII digits: 0 1 2 3 4 5 6 7 8 9.

This is not the same question as https://stackoverflow.com/questions/894263/how-do-i-identify-if-a-string-is-a-number, since this question is not only about how to identify, but also about what the fastest method for doing so is.

C# Solutions


Solution 1 - C#

bool IsDigitsOnly(string str)
{
	foreach (char c in str)
	{
		if (c < '0' || c > '9')
			return false;
	}

	return true;
}

Will probably be the fastest way to do it.

Solution 2 - C#

You could do this simply using LINQ:

return str.All(char.IsDigit);

  1. .All returns true for empty strings and throws an exception for null strings.
  2. char.IsDigit is true for all Unicode digit characters.

Solution 3 - C#

Here's some benchmarks based on 1000000 parses of the same string:

Updated for release stats:

IsDigitsOnly: 384588
TryParse:     639583
Regex:        1329571

Here's the code, looks like IsDigitsOnly is faster:

class Program
{
    private static Regex regex = new Regex("^[0-9]+$", RegexOptions.Compiled);

    static void Main(string[] args)
    {
        Stopwatch watch = new Stopwatch();
        string test = int.MaxValue.ToString();
        int value;
        
        watch.Start();
        for(int i=0; i< 1000000; i++)
        {
            int.TryParse(test, out value);
        }
        watch.Stop();
        Console.WriteLine("TryParse: "+watch.ElapsedTicks);

        watch.Reset();
        watch.Start();
        for (int i = 0; i < 1000000; i++)
        {
            IsDigitsOnly(test);
        }
        watch.Stop();
        Console.WriteLine("IsDigitsOnly: " + watch.ElapsedTicks);

        watch.Reset();
        watch.Start();
        for (int i = 0; i < 1000000; i++)
        {
            regex.IsMatch(test);
        }
        watch.Stop();
        Console.WriteLine("Regex: " + watch.ElapsedTicks);

        Console.ReadLine();
    }

    static bool IsDigitsOnly(string str)
    {
        foreach (char c in str)
        {
            if (c < '0' || c > '9')
                return false;
        }

        return true;
    }
}

Of course it's worth noting that TryParse does allow leading/trailing whitespace as well as culture specific symbols. It's also limited on length of string.

Solution 4 - C#

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

Solution 5 - C#

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

Solution 6 - C#

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

Solution 7 - C#

Function with empty validation:

public static bool IsDigitsOnly(string str)
  {             
        return !string.IsNullOrEmpty(str) && str.All(char.IsDigit);
  }

Solution 8 - C#

I like Linq and to make it exit on first mismatch you can do this

string str = '0129834X33';
bool isAllDigits = !str.Any( ch=> ch < '0' || ch > '9' );

Solution 9 - C#

if it is a single string :

if (str.All(Char.IsDigit))
{
  // string contains only digits
}

if it is a list of strings :

if (lstStr.All(s => s.All(Char.IsDigit)))
{
  // List of strings contains only digits
}

Solution 10 - C#

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 )

Solution 11 - C#

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.

Solution 12 - C#

You can do this in a one line LINQ statement. OK, I realise this is not necessarily the fastest, so doesn't technically answer the question, but it's probably the easiest to write:

str.All(c => c >= '0' && c <= '9')

Solution 13 - C#

This might be coming super late!, but I'm sure it will help someone, as it helped me.

        private static bool IsDigitsOnly(string str)
        {
            return str.All(c => c >= '0' && c <= '9');
        }

Solution 14 - C#

You can try using Regular Expressions by testing the input string to have only digits (0-9) by using the .IsMatch(string input, string pattern) method in C#.

using System;
using System.Text.RegularExpression;

public namespace MyNS
{
    public class MyClass
    {
        public void static Main(string[] args)
        {
             string input = Console.ReadLine();
             bool containsNumber = ContainsOnlyDigits(input);
        }

        private bool ContainOnlyDigits (string input)
        {
            bool containsNumbers = true;
            if (!Regex.IsMatch(input, @"/d"))
            {
                containsNumbers = false;
            }
            return containsNumbers;
        }
    }
}

Regards

Solution 15 - C#

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
    }

Solution 16 - C#

Another approach!

string str = "12345";
bool containsOnlyDigits = true;
try { if(Convert.ToInt32(str) < 0){ containsOnlyDigits = false; } }
catch { containsOnlyDigits = false; }

Here, if the statement Convert.ToInt32(str) fails, then string does not contain digits only. Another possibility is that if the string has "-12345" which gets converted to -12345 successfully, then there is a check for verifying that the number converted is not less than zero.

Solution 17 - C#

Try this code:

bool isDigitsOnly(string str)
{
   try
   {
      int number = Convert.ToInt32(str);
      return true;
   }
   catch (Exception)
   {
      return false;
   }
}

Solution 18 - C#

What about char.IsDigit(myChar)?

Solution 19 - C#

Very Clever and easy way to detect your string is contains only digits or not is this way:

string s = "12fg";

if(s.All(char.IsDigit))
{
   return true; // contains only digits
}
else
{
   return false; // contains not only digits
}

Solution 20 - C#

public bool CheckforDigits(string x)
{    
    int tr;  
    return x.All(r=> int.TryParse(r.ToString(), out tr));
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNahumView Question on Stackoverflow
Solution 1 - C#jakobbotschView Answer on Stackoverflow
Solution 2 - C#UdayView Answer on Stackoverflow
Solution 3 - C#TheCodeKingView Answer on Stackoverflow
Solution 4 - C#flaynView Answer on Stackoverflow
Solution 5 - C#SlaiView Answer on Stackoverflow
Solution 6 - C#Branko DimitrijevicView Answer on Stackoverflow
Solution 7 - C#i31nGoView Answer on Stackoverflow
Solution 8 - C#AlobidatView Answer on Stackoverflow
Solution 9 - C#Ah Sa FaView Answer on Stackoverflow
Solution 10 - C#AtulyaView Answer on Stackoverflow
Solution 11 - C#Petar IvanovView Answer on Stackoverflow
Solution 12 - C#Stephen HoltView Answer on Stackoverflow
Solution 13 - C#user8107351View Answer on Stackoverflow
Solution 14 - C#Jason CidrasView Answer on Stackoverflow
Solution 15 - C#Hossein ElDelbaniView Answer on Stackoverflow
Solution 16 - C#Ali SajjadView Answer on Stackoverflow
Solution 17 - C#H. BorsipourView Answer on Stackoverflow
Solution 18 - C#MirkoView Answer on Stackoverflow
Solution 19 - C#Avtandil KavrelishviliView Answer on Stackoverflow
Solution 20 - C#ReRView Answer on Stackoverflow