简体   繁体   中英

How can I make my if statements less contradictory?

I have a points system for a password strength checker that I am working on.

Currently the rules work like something this: +5 if the user entry has a lower case letter, +10 if it has a lower and upper case letter, a number or a special character,etc.

The problem I have ran into is that my if statements are contradictory and I was wandering if there were any alternatives I could use.

The statements below is me trying to get it so if they put in a certain type of character, they will gain points and it will contribute to the score, ie if it has a number, then +5 to the score.

if (userPassword.Any(char.IsDigit))
{
    points += 5;
}

if (userPassword.Any(char.IsLower))
{
    points += 5;
}

if (userPassword.Any(char.IsUpper))
{
    points += 5;
}

if (userPassword.Any(c => specialCharacters.Contains(c)))
{
    points += 5;
}

To get rid of the contradiction, I tried to do an.all function on the statements that potentially deduct points of the user, but it seems inadequate and I don't think it is quite right for this programme.

I am basically trying to get it to deduct points if the user is using only one type of character, ie if they only use numbers and nothing else they will lose points.

if (userPassword.All(char.IsLower) || userPassword.All(char.IsUpper)) 
{
    points -= 5;
}

if (userPassword.All(char.IsDigit)) 
{
    points -= 5;
}

if (userPassword.All(c => specialCharacters.Contains(c))) 
{
    points -= 5;
}

What would be an alternative to solve this?

EDIT: Ok thank you for clarifying that there isn't anything wrong with my if statements. I now want to add an if statement that adds 10 points if it contains an upper case, lower case, digit and special character. I have tried to use the.contain statement to try and differentiate it from the other addition if statements but it is giving me an error of Argument 1: Cannot Convert from 'method group' to 'string'and I don't know what to use to bypass it.

if (userPassword.Contains(char.IsUpper) &&
    userPassword.Contains(char.IsLower) &&
    userPassword.Contains(char.IsDigit) &&
    userPassword.Contains(c => specialCharacters.Contains(c)))
{
    points += 10;
}

If I'm understanding correctly, you want passwords which fit the "all uppercase," et cetera conditionals to subtract points while also NOT adding points for having a single uppercase. Like currently, "abc" in your example would receive +5 for having one lowercase, then would lose 5 for having all lowercase, evening out to 0 rather than -5.

I would put your point-deducting conditionals into a single if statement at the beginning, then put all of your point-adding conditionals into if statements within an else statement:

 if (userPassword.All(char.IsLower) || userPassword.All(char.IsUpper) || userPassword.All(char.IsDigit) || userPassword.All(c => specialCharacters.Contains(c)) { points -= 5; } else { if (userPassword.Any(char.IsDigit)) { points += 5; } if (userPassword.Any(char.IsLower)) { points += 5; } if (userPassword.Any(char.IsUpper)) { points += 5; } if (userPassword.Any(c => specialCharacters.Contains(c))) { points += 5; } }

Alternatively, if you needed those point-deducting conditionals to be separated to allow for different values of point deductions for different conditions, just use more else if statements for the bad ones:

 if (userPassword.All(char.IsLower) || userPassword.All(char.IsUpper)) { points -= 5; } else if (userPassword.All(char.IsDigit)) { points -= 5; } else if (userPassword.All(c => specialCharacters.Contains(c))) { points -= 5; } else { if (userPassword.Any(char.IsDigit)) { points += 5; } if (userPassword.Any(char.IsLower)) { points += 5; } if (userPassword.Any(char.IsUpper)) { points += 5; } if (userPassword.Any(c => specialCharacters.Contains(c))) { points += 5; } }

Combine your "contradiction" check with the relevant "affirmation" check. For example, when testing for containing a digit, also ensure they're not all digits:

if( userPassword.Any(char.isDigit)
    && !userPassword.All(char.isDigit) )
{
    points += 5;
}
else /*if(userPassword.All(char.isDigit)*/ // if desired
{
    points -= 5; // if appropriate
}

Now lets discuss restructuring your algorithm. Instead of defining long chains of if or if/else statements, let's create a class you can use to define your checks:

public class PasswordEvaluator
{
    public Func<string, bool> TestCondition { get; init set; }
    public int AffirmativeResultValue { get; init set; }
    public int NegativeResultValue { get; init set; }

    public int Evaluate(string password) =>
        TestCondition(password)
            ? AffirmativeResultValue 
            : NegativeResultValue ;
}

Then you can define your tests. Using the above solution:

var hasDigitEvaluator = new PasswordEvaluator
{
    Condition = (string password) => password.Any(char.isDigit)
        && !password.All(char.isDigit),
    AffirmativeResultValue = 5,
    NegativeResultValue = -5, // or 0, whatever
};

Then you can use this object to perform the operation:

points += hasDigitEvaluator.Evalutate(userPassword);

Now, to handle multiple evaluators, you can compose an IEnumerable<PasswordEvaluator> and then call a single operation over it to get your aggregate result:

var passwordEvaluators = new[]
{
    new PasswordEvaluator { ... },
    new PasswordEvaluator { ... },
    ...
};

var points = passwordEvaluators
    .Select(test => test.Evaluate(userPassword))
    .Sum();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM