6

I am looking for an elegant way, preferably a short linq expression, to count how many alphanumeric chars a given string contains.

The 'boring' way I do it now is this:

int num = 0;
for (int i = 0; i < password.Length; i++)
{
    if (!char.IsLetterOrDigit(password, i))
    {
        num++;
    }
}
if (num < MinRequiredNonAlphanumericCharacters)
    return false;

This is rather short already, but I am sure with some linq magic this can be done in an even shorter, equally understandable expression, right?

magnattic
  • 12,638
  • 13
  • 62
  • 115
  • The linq way won't lend itself as well to a very good optimization, which is to stop searching the string once you have enough alphanumeric characters. Okay given the context of passwords and their length, maybe it's not a 'very good' optimization... – corsiKa Jul 19 '12 at 22:01
  • @corsiKa i don't think he's going for optimization so much elegant-tizing/syntactic sugaring... – Giovanni B Jul 19 '12 at 22:05
  • That's right, I am doing PBKDF2 hashing right after that part, so a few milliseconds here are not the issue anyway. – magnattic Jul 19 '12 at 22:08

4 Answers4

19

Here's the quick and dirty LINQ way to get the letter & digit count:

password.Count(char.IsLetterOrDigit)

This is more of a direct copy of what you're doing:

password.Count(c => !char.IsLetterOrDigit(c))
Austin Salonen
  • 49,173
  • 15
  • 109
  • 139
2
int num = password.Where((t, i) => !char.IsLetterOrDigit(password, i)).Count();

if (num < MinRequiredNonAlphanumericCharacters)
    return false;
HatSoft
  • 11,077
  • 3
  • 28
  • 43
  • The Where is unnecessary here as you can do the same check in Count – Austin Salonen Jul 19 '12 at 22:10
  • @AustinSalonen as you can see various ways have already been showed on this page as answers, I personally find Where easy to use, its the first extension method that comes in my mind – HatSoft Jul 19 '12 at 22:13
0

You could do it with one line of Regex. Whether that's understandable is a moot point.

num = new Regex(@"\w", RegexOptions.IgnoreCase).Matches(input).Count
podiluska
  • 50,950
  • 7
  • 98
  • 104
0

You can use Take() to ensure that you don't inspect more letters than necessary:

int minCount = password.Where(x => !char.IsLetterOrDigit(x)).Take(MinRequired).Count();
if (minCount < MinRequired) { // No good }

The idea is that we only keep checking until you've hit the minimum number. At that point, we can stop, because we know we have an admissible password. Take() takes as many as it can, and no more, so if there aren't enough, it will just return a number less than you've requested.

dlev
  • 48,024
  • 5
  • 125
  • 132