1

i have to add validator for password column, i.e. it should not allow "Password" word in Password at any stage.. means "Password@1234" should not be allowed. So i was using below code which is working fine:

Regex.IsMatch(viewModel.Password.ToUpper(), @"(\w*PASSWORD\w*)", RegexOptions.IgnoreCase)

Now i want to compare multiple words means it should not contains "Password" or "Hello" lets say. I have tried ".Any" but it is not working.

if (myList.Any(str => str.Contains("Password")))

I have followed:

Check if a string within a list contains a specific string with Linq

for Any

Please help.

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
Ram Singh
  • 6,664
  • 35
  • 100
  • 166
  • what do you mean by multiple 'words'? do you mean a sentence still stored as a string such as "this has many words" or do you mean a collection of words like `List {"this", "is", "a", "collection", "of", "words"}` – Dave Feb 06 '20 at 09:32
  • List {"this", "is", "a", "collection", "of", "words"} – Ram Singh Feb 06 '20 at 09:32
  • so what exactly have you tried? You've said you tried `Any()`.. what did this code look like? – Dave Feb 06 '20 at 09:33
  • 1
    thats because you've changed what you are checking... your first example is doing a regex check on an uppercased version of the password. Your `Any` version is just doing a basic contains – Dave Feb 06 '20 at 09:37

3 Answers3

3

Yes, you can try Linq Any (word definition is a complex question, that's why let me stick to your pattern: \w*{word_to_find}\w*):

  List<string> ForbiddenWords = new List<string>() {
    "this",
    "password",
    "bla-bla-bla",
    "123",
  };

  Regex[] invalidPasswords = ForbiddenWords
    .Select(word => new Regex($@"\w*{Regex.Escape(word)}\w*", RegexOptions.IgnoreCase))
    .ToArray();

  ...

  if (invalidPasswords.Any(regex => regex.IsMatch(viewModel.Password))) {
    // Password is invalid it contains forbidden word(s)
  } 

Let's have some demonstration:

  string[] tests = new string[] {
    "MyPassWord",
    "PassWord",
    "PassWord@123",
    "PassWord@5678",
    "It's_PassWord@5678",
    "ABC123",
    "123",
    "1234",
    "pass",
    "word",
    "swar",
  };

  Func<string, bool> Validator = (password) => 
    !invalidPaswords.Any(regex => regex.IsMatch(password));

  string report = string.Join(Environment.NewLine, tests
    .Select(test => $"{test,-20} : {(Validator(test) ? "OK" : "Invalid")}"));

  Console.Write(report);

Outcome:

MyPassWord           : Invalid
PassWord             : Invalid
PassWord@123         : Invalid
PassWord@5678        : Invalid
It's_PassWord@5678   : Invalid
ABC123               : Invalid
123                  : Invalid
1234                 : Invalid
pass                 : OK
word                 : OK
swar                 : OK
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • @Ram Singh: `Password@1234` is *invalid*: it contains `password` and `123` forbidden words; – Dmitry Bychenko Feb 06 '20 at 09:45
  • no, because \w* which would be for: a-z, A-Z, 0-9 and underscore. If you add a special char, it won't work and regex.IsMatch will return false. – Lucca Ferri Feb 06 '20 at 09:46
  • @DmitryBychenko it won't be invalid. Your regex expression is expecting only words (and forbidden words). It will never match. Don't use regex for that. – Lucca Ferri Feb 06 '20 at 09:48
  • @Lucca Ferri: *word definition* is a *complex question* (is it a sequence of letters or digits, any text between `\s`, `\b` etc), that's why I've just taken the pattern from the question – Dmitry Bychenko Feb 06 '20 at 09:48
0

Maybe your .Any is wrong. Have you tried this?

    static bool ContainsBlacklistedWords(string password, string[] blacklist)
    {
        return blacklist.Any(s => password.Contains(s, StringComparison.CurrentCultureIgnoreCase));
    }
    static void Main(string[] args)
    {
        string password = "foobar";
        string[] blacklist = new[] { "hello", "password" };

        if (ContainsBlacklistedWords(password, blacklist))
        {
            Console.WriteLine("Contains blocked words.");
        }
        else
        {
            Console.WriteLine("OK");
        }
     }

Works just fine. No Regex needed.


This is wrong:

if (myList.Any(str => str.Contains("Password")))

this would be something like (example for explaination only):

foreach (var str in myList)
{
      if (str.Contains("Password"))
      {
              return true;
      }
}
return false;

So, in this code above (which is logically the same as the Any()), where are you feeding the password? You are looping the list searching for "Password", and not checking a password against a list.

If you use the method that I showed above, it should work the way you like it. I wouldn't regex that, especially if your list is big.

Lucca Ferri
  • 1,308
  • 12
  • 23
-1

You can try the followings,

By regex

bool res = Regex.IsMatch(viewModel.Password.ToUpper(), @"(\w*PASSWORD\w*)|(\w*HELLO\w*)", RegexOptions.IgnoreCase);

or

By LINQ

var forbiddenWords = new List<string>() { "PASSWORD", "HELLO" };
bool res = forbiddenWords.Any(x => viewModel.Password.ToUpper().Contains(x));
Furkan Öztürk
  • 1,178
  • 11
  • 24