Okay so I have a long string of digits, but I need to make sure it hasn't got any digits, whats the easiest way to do this?
-
1*Compiled* Regular Expressions. – qJake May 15 '13 at 13:45
-
8You need to start being consistent - are you looking for letters or digits? Your title and body differ. Also, if you have "a long string of digits" but you "need to make sure it hasn't got any digits" that sounds like a problem. Attention to detail is important when asking a question. – Jon Skeet May 15 '13 at 13:48
-
@JonSkeet you are right! I just read it as "string of digits, be sure there are no non-digit chars".. – Lorenzo Dematté May 15 '13 at 14:14
-
As you can see in my title it says contains any letters or not? meaning it could be either – user2294174 May 15 '13 at 14:29
-
@user2294174 both the tile and the body are ambiguous, please edit your question instead of commenting. With a little effort, you can make sure you have a correct answer! – Lorenzo Dematté May 15 '13 at 14:36
5 Answers
You could use char.IsDigit
:
var containsOnlyDigits = "007".All(char.IsDigit); // true

- 57,867
- 14
- 111
- 145
-
He mentioned the string was very long ... LINQ is extremely inefficient at these types of things. – qJake May 15 '13 at 13:48
-
@SpikeX I don't think so.. it is for sure bettere than a regex, and better than trying to parse it! – Lorenzo Dematté May 15 '13 at 13:49
-
@SpikeX Well, it's not that slow. The enumeration is stopped as soon as the result can be determined. – alexn May 15 '13 at 13:50
-
It will only fail fast if there is a character early in the string, what if the string is *huge* and the characters are at the end? It's all speculation, you can't really say one approach is faster than the other unless it's been benchmarked. – James May 15 '13 at 13:54
-
I really think LINQ is fast enough, but anyway you can do the same using foreach or for() – Lorenzo Dematté May 15 '13 at 13:55
-
@James Of course, but you really need to check every character to determine if it contains a character. – alexn May 15 '13 at 13:55
-
@alexn hence my point, a compiled regex could *potentially* be faster than LINQ here. – James May 15 '13 at 13:56
-
@James, true! I think that both saying "it is fast" and "LINQ is extremely inefficient" does not do any good without benchmarks – Lorenzo Dematté May 15 '13 at 13:56
-
@James it could... but I really do not see why :) after all, how can it be more efficient? – Lorenzo Dematté May 15 '13 at 13:57
-
@dema80 well regexes are built specifically for text matching therefore I would *assume* it would be a bit smarter than going through every character in the string (which is effectively what your LINQ expression will do). I don't know how the regex engines work under the hood though so this is only my assumption - again it would need to be benchmarked for clarity. – James May 15 '13 at 14:03
-
@James the point is that (in big-O notation) it can not get better than that: in the worst case (all chars are digits) you need to scan all the character in the string to find if any one is not a digit. Besides, regular expressions are a general purpose mechanism; as you said, they are build for text matching, therefore I would assume it would be a bit slower than a specifically designed function. That said, I might be surprised by a benchmark... – Lorenzo Dematté May 15 '13 at 14:07
-
Not exactly the same, but gives you an idea of looping VS regex speed http://stackoverflow.com/questions/473087/string-benchmarks-in-c-sharp-refactoring-for-speed-maintainability – Lorenzo Dematté May 15 '13 at 14:11
-
@dema80 not *really* a fair test, the string is really small, my point is over a large string I think a regex *may* be more efficient. – James May 15 '13 at 14:21
-
@James yes, I understand your point and I am with you that benchmarking is in order. Unfortunately, I do not have a C# compiler on my linux box... My money is on a for() loop though ;) and I would even bet on the LINQ solution being faster than e regex! I hope someone can come up with benchmarks, or we will have to wait I get home :) – Lorenzo Dematté May 15 '13 at 14:35
-
1@James finally I had the time to fire up my portable, and benchmark it! – Lorenzo Dematté May 16 '13 at 07:30
Scan the string, test the char... s.All(c => Char.IsDigit(c))
Enumerable.All will exit as soon as it finds a non-digit characted. IsDigit is very fast at checking the char. Cost is O(N) (as good as it can get); for sure, it is bettet than trying to parse the string (which will fail if the string is really long) or use a regexpr...
If you try this solution and see it is too slow for you, you can always go back to good old loops to scan the string..
foreach (char c in s) {
if (!Char.IsDigit(c))
return false;
}
return true;
or even better:
for (int i = 0; i < s.Length; i++){
if (!Char.IsDigit(s[i]))
return false;
}
return true;
EDIT: Benchmarks, at last!
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
namespace FindTest
{
class Program
{
const int Iterations = 1000;
static string TestData;
static Regex regex;
static bool ValidResult = false;
static void Test(Func<string, bool> function)
{
Console.Write("{0}... ", function.Method.Name);
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
bool result = function(TestData);
if (result != ValidResult)
{
throw new Exception("Bad result: " + result);
}
}
sw.Stop();
Console.WriteLine(" {0}ms", sw.ElapsedMilliseconds);
GC.Collect();
}
static void InitializeTestDataEnd(int length)
{
TestData = new string(Enumerable.Repeat('1', length - 1).ToArray()) + "A";
}
static void InitializeTestDataStart(int length)
{
TestData = "A" + new string(Enumerable.Repeat('1', length - 1).ToArray());
}
static void InitializeTestDataMid(int length)
{
TestData = new string(Enumerable.Repeat('1', length / 2).ToArray()) + "A" + new string(Enumerable.Repeat('1', length / 2 - 1).ToArray());
}
static void InitializeTestDataPositive(int length)
{
TestData = new string(Enumerable.Repeat('1', length).ToArray());
}
static bool LinqScan(string s)
{
return s.All(Char.IsDigit);
}
static bool ForeachScan(string s)
{
foreach (char c in s)
{
if (!Char.IsDigit(c))
return false;
}
return true;
}
static bool ForScan(string s)
{
for (int i = 0; i < s.Length; i++)
{
if (!Char.IsDigit(s[i]))
return false;
}
return true;
}
static bool Regexp(string s)
{
// String contains numbers
return regex.IsMatch(s);
// String contains letters
//return Regex.IsMatch(s, "\\w", RegexOptions.Compiled);
}
static void Main(string[] args)
{
regex = new Regex(@"^\d+$", RegexOptions.Compiled);
Console.WriteLine("Positive (all digitis)");
InitializeTestDataPositive(100000);
ValidResult = true;
Test(LinqScan);
Test(ForeachScan);
Test(ForScan);
Test(Regexp);
Console.WriteLine("Negative (char at beginning)");
InitializeTestDataStart(100000);
ValidResult = false;
Test(LinqScan);
Test(ForeachScan);
Test(ForScan);
Test(Regexp);
Console.WriteLine("Negative (char at end)");
InitializeTestDataEnd(100000);
ValidResult = false;
Test(LinqScan);
Test(ForeachScan);
Test(ForScan);
Test(Regexp);
Console.WriteLine("Negative (char in middle)");
InitializeTestDataMid(100000);
ValidResult = false;
Test(LinqScan);
Test(ForeachScan);
Test(ForScan);
Test(Regexp);
Console.WriteLine("Done");
}
}
}
I tested positive, and three negatives, to 1) test which regex is the correct one, 2) look for confirmation of a suspect I had...
My opinion was that Regexp.IsMatch
had to scan the string as well, and so it seems to be:
Times are consistent with scans, only 3x worse:
Positive (all digitis)
LinqScan... 952ms
ForeachScan... 1043ms
ForScan... 869ms
Regexp... 3074ms
Negative (char at beginning)
LinqScan... 0ms
ForeachScan... 0ms
ForScan... 0ms
Regexp... 0ms
Negative (char at end)
LinqScan... 921ms
ForeachScan... 958ms
ForScan... 867ms
Regexp... 3986ms
Negative (char in middle)
LinqScan... 455ms
ForeachScan... 476ms
ForScan... 430ms
Regexp... 1982ms
Credits: I borrowed the Test function from Jon Skeet
Conclusions: s.All(Char.IsDigit)
is efficient, and really easy (which was the original question, after all). Personally, I find it easier than regular expressions (I had to look on SO which was the correct one, as I am not familiar with C# regexp syntax - which is standard, but I didn't know - and the proposed solution was wrong).
So.. measure, and don't believe in myths like "LINQ is slow" or "RegExp are slow".
After all, they are both OK for the task (it really depends on what you need it for), pick the one you prefer.

- 7,638
- 3
- 37
- 77
-
You probably meant Char.IsDigit(c). However, this is the fastest solution of them all. – Candide May 15 '13 at 14:20
-
@Candide ops, I forgot Char was static.. Thanks! I will edit my answer – Lorenzo Dematté May 15 '13 at 14:30
-
Last try: I replaced `Char.IsDigit` with `(c < '0' || c > '9')`; it makes no difference (IsDigit is as good as it gets) – Lorenzo Dematté May 16 '13 at 07:36
-
+1 I stand corrected, a compiled regex is *wayyy* slower. Interesting to see that LINQ is actually faster than `foreach`. – James May 16 '13 at 09:42
-
@James I was surprised too to see LINQ faster than foreach, because I thought that All was implemented using foreach internally! – Lorenzo Dematté May 16 '13 at 11:34
-
Damn ... Regex really is slow, even when it's compiled. I would have never guessed. – qJake May 16 '13 at 13:37
Use regular expressions:
using System.Text.RegularExpressions;
string myString = "some long characters...";
if(Regex.IsMatch(myString, @"^\d+$", RegexOptions.Compiled))
{
// String contains only numbers
}
if(Regex.IsMatch(myString, @"^\w+$", RegexOptions.Compiled))
{
// String contains only letters
}

- 16,821
- 17
- 83
- 135
-
I don't think your regex does what is needed.. it should be at least `"\\d"`, or `@"\d"`, but better yet it should be like in this answer http://stackoverflow.com/a/273144/863564, or it will match any string that has a digit in it. – Lorenzo Dematté May 16 '13 at 07:29
-
At the time, the OP's question was very vague, so my answer matched the question. I fixed up the answer a bit. – qJake May 16 '13 at 13:34
Try using TryParse
bool longStringisInt = Int64.TryParse(longString, out number);
If the string (i.e. longString) cannot be converted to an int (i.e. has letters in it) then the bool is false, otherwise it would be true.
EDIT: Changed to Int64 to ensure wider coverage

- 4,888
- 3
- 28
- 44
-
1Not really reliable, this would fail for anything above 2147483647. If you were to use this approach it would be better to use `Int64.TryParse`. – James May 15 '13 at 13:49
-
@James - true, but assumed (maybe wrongly) we are dealing with smaller numbers. Edited answer to include your suggestion. – AMadmanTriumphs May 15 '13 at 13:50
You can use IndexOfAny
bool containsDigits = mystring.IndexOfAny("0123456789".ToCharArray()) != -1;
In Linq you'd have to do:
bool containsDigits = mystring.Any(char.IsDigit);
Edit:
I timed this and it turns out the Linq solution is slower.
For string length 1,000,000 the execution time is ~13ms for the linq solution and 1ms for IndexOfAny
.
For string length 10,000,000 the execution time for Linq is still ~122ms, whereas IndexOfAny
is ~18ms.

- 30,469
- 8
- 53
- 60
-
Nice solution! Would love to see how it compares to scan the string and use "IsDigit", performance wise.. – Lorenzo Dematté May 15 '13 at 13:53
-
thank you for the benchmark! I expect a for() loop to be slightly faster, but LINQ is not bad at all.. :) – Lorenzo Dematté May 15 '13 at 14:12
-
@dema80 I stand corrected. I was testing the linq solution with `All` and that's incorrect. To check if there is a number you have to use `Any` as above. So, yes, linq is slower. – Candide May 15 '13 at 14:18
-
the problem is.. as Jon pointed out in a comment, the question is ambiguous. Are we looking for a string that is made only of digits? Then `All(IsDigit)` is correct. Why should you use Any? Even if it is equivalent, `Any(!c.IsDigit)` will scan the whole string – Lorenzo Dematté May 15 '13 at 14:19
-
a fair comparison will use All, not Any, as any will scan the whole string. If you want to test for the "reverse" condition (string does not contain any digit) you should use All(!char.IsDigit), not Any(char.IsDigit). They are equivalent, but the second will always scan the whole array. – Lorenzo Dematté May 16 '13 at 07:03
-
I was testing the worse case, where you have one digit in the end of the string. Actually, the lambda is `c => !char.IsDigit(c)`. Which is actually slower, because not only is it evaluating a function, it is also computing the negation. It will still traverse the whole string in the worse case. Timing a string of 10,000,000 characters, `All` takes 146ms, and `Any` 110ms. – Candide May 16 '13 at 08:56
-
Ok for the worst case: in that case they match. Still, I think you should use `All(!IsDigit)`, as it is better in the general case. And if you are really care about performance, just use a `for()` – Lorenzo Dematté May 16 '13 at 09:14
-
BTW, I was not able to insert your solution in my benchmarks, because I have interpreted the question in the other way, and my functions test if there is any non-digit in the string. In that case, I cannot use IndexOfAny – Lorenzo Dematté May 16 '13 at 09:16
-
:D I read the second part of OPs question, and tested if the string contains **any** digits. – Candide May 16 '13 at 09:20