1

I have the following method:

        public static bool isUeiFormatOK(string test)
        {
            string pattern = "[A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9][A-Za-z0-9]";
            MatchCollection matches;
            Regex regex = new Regex(pattern);
            matches = regex.Matches(test);

            if (matches.Count == 0)
                return false;

            return true;
        }

This validates that a string is 12 characters and contains numbers or letters.

How do I say, that one of the char must be a number?

KeithL
  • 5,348
  • 3
  • 19
  • 25
  • What do you want to match? You could simplify this with `[A-Za-z0-9]{12}`. Do you mean that all characters must be alphanumeric but one of them at least must be a digit? – Panagiotis Kanavos Dec 20 '21 at 15:56
  • 1
    You can assert a single digit `^(?=[A-Za-z]*[0-9])[A-Za-z0-9]{12}$` – The fourth bird Dec 20 '21 at 15:57
  • I am trying to also say that one of the 12 char must be a number but any one of them – KeithL Dec 20 '21 at 15:57
  • You could also use `\w{12}` if you're OK with non-English characters. `\w` means word character. You can replace `[0-9]` with `\d` – Panagiotis Kanavos Dec 20 '21 at 15:58
  • @PanagiotisKanavos. Yes that is what i am attempting – KeithL Dec 20 '21 at 15:58
  • Consider reading this answer: https://stackoverflow.com/questions/17342626/regular-expression-for-at-least-one-number. the basic idea is `.*[0-9].*` But replace `.` with whatever other requirements you have. e.g.: `[A-Za-z0-9]` – Wyck Dec 20 '21 at 15:58

3 Answers3

5

You can use a quantifier {12} to shorten the pattern, and use a positive lookahead to assert a digit, first optionally matching the same allowed characters of the character class without the digits.

^(?=[A-Za-z]*[0-9])[A-Za-z0-9]{12}$
  • ^ Start of string
  • (?=[A-Za-z]*[0-9]) Positive lookahead, assert optional chars A-Za-z to the right followed by a digit
  • [A-Za-z0-9]{12} Match 12 occurrences of either a char A-Za-z or a digit 0-9
  • $ End of string ( Or use \z)

You don't have to count the number of matches, you can return the value of IsMatch instead.

public static bool isUeiFormatOK(string test)
{
    return new Regex("^(?=[A-Za-z]*[0-9])[A-Za-z0-9]{12}$").IsMatch(test);
}
The fourth bird
  • 154,723
  • 16
  • 55
  • 70
  • I'm sure this works, but can you help me understand what this means... ^(?=[A-Za-z]*[0-9]). The second part is clear. – KeithL Dec 20 '21 at 16:09
  • 1
    It's a "positive lookahead". It basically means "this is only a match if the string from this point matches the given pattern". In your case, the string only matches if it contains 0 or more letters followed by a number. – D Stanley Dec 20 '21 at 16:14
2

For readability, it's best to use two different matches, but it can be done with one.

^
(?= .* [0-9] )
[A-Za-z0-9]{12}
$

(?= ... ) is a lookahead. It matches zero characters, but only succeeds if the interior pattern matches at the current location.

Complete solution:

private static Regex valid_re = new Regex(
   @"
      ^
      (?= .* [0-9] )
      [A-Za-z0-9]{12}
      $
   ",
   RegexOptions.IgnorePatternWhitespace // | RegexOptions.Compiled 
);

public static bool isUeiFormatOK(string test) {
   return valid_re.IsMatch(test);
}
ikegami
  • 367,544
  • 15
  • 269
  • 518
0

You could also do it with plain C# code.

public static bool IsUeiFormatOk(string input)
{
    bool hasDigit = false;

    foreach (char character in input)
    {
        if (char.IsDigit(character))
        {
            hasDigit = true;
            continue;
        }

        if (IsEnglishLetter(character))
        {
            continue;
        }

        return false;
    }

    return hasDigit;
}

public static bool IsEnglishLetter(this char letter) =>
    letter is >= 'a' and <= 'z' or >= 'A' and <= 'Z';
msmolcic
  • 6,407
  • 8
  • 32
  • 56