简体   繁体   English

检查某些字符是否在 C 的字符串中

[英]checking if certain characters are in a string in C

Hi I'm a newbie C learner and this is an assignment.嗨,我是新手 C 学习者,这是一个作业。

The task is to write a program that changes a user's password and check if the new given password includes at least a number, a letter and one of these ( @ , # , $ , % ) signs and its length should be between 6 and 20.任务是编写一个更改用户密码的程序,并检查新的给定密码是否至少包含一个数字、一个字母和其中一个( @#$% )符号,其长度应在 6 到 20 之间.

I've described 3 variables as counter1 , counter2 & counter3 to check if at least a sign, a number & a letter is in the given password and if one of them was 0 scan another password from the user.我已经将 3 个变量描述为counter1counter2counter3来检查给定密码中是否至少有一个符号、一个数字和一个字母,如果其中一个是 0,则从用户那里扫描另一个密码。 This should continue until an entered password includes all the terms above.这应该一直持续到输入的密码包含上述所有条款。

My program will check the numbers, letters & the signs in given password but as the first new password is entered the program will end whether it contains all the terms or not, this is the part of the program that I assume the problem is from我的程序将检查给定密码中的数字、字母和符号,但是当输入第一个新密码时,无论是否包含所有条款,程序都会结束,这是我认为问题出在程序的一部分

int counter1 = 0, counter2 = 0, counter3 = 0;
char mypassword[20] = "A1$B2C";
char password[20];
char newpassword[50];
int check = 0;
do {
    printf("Please enter your current password: ");
    scanf("%s", password);
} while (strcmp(mypassword, password) != 0);
printf("Please enter your new password: ");
scanf("%s", newpassword);

for (int i = 0; i < strlen(newpassword); i++) {
    if (isalpha(newpassword[i]) != 0) {
        counter3 += 1;
    }
    else if (isdigit(newpassword[i]) != 0) {
        counter2 += 1;
    }
    else if (newpassword[i] == '@' || '#' || '$' || '%') {
        counter1 += 1;
    }
}
while (check == 0) {
    while (counter1 == 0 || counter2 == 0 || counter3 == 0) {
        printf("Please enter you new password: ");
        scanf("%s", newpassword);
    }
    if (strlen(newpassword) < 6 || strlen(newpassword) > 20) {
        printf("Please enter you new password: ");
        scanf("%s", newpassword);
    }
    else
        check += 1;
}

The test for special characters is incorrect: if (newpassword[i] == '@' || '#' || '$' || '%') will always succeed because '#' taken as a boolean is true.特殊字符的测试不正确: if (newpassword[i] == '@' || '#' || '$' || '%')将始终成功,因为将'#'视为 boolean 为真。

You should instead write:你应该写:

int c = newpassword[i];
if (c == '@' || c == '#' || c == '$' || c == '%') {
    counter1++;
}

There are other problems in your code:您的代码中还有其他问题:

  • you do not pass a maximum number of characters for scanf() to read into password : any input word longer than 19 bytes will cause undefined behavior.您没有为scanf()传递最大字符数以读取password :任何超过 19 个字节的输入字都会导致未定义的行为。

  • you do not test for scanf() failure: unexpected end of file will cause undefined behavior and likely an endless loop.您不测试scanf()失败:文件意外结束将导致未定义的行为,并可能导致无限循环。

  • you should be more explicit about the reason for prompting for the new password again.您应该更明确地说明再次提示输入新密码的原因。

  • the counters should be reset to 0 for each new password entered and their names should be more meaningful.对于输入的每个新密码,计数器应重置为0 ,并且它们的名称应该更有意义。

  • all tests must be tried again for every new attempt: Use a for loop with a single instance of scanf() to read the current or new password, perform the tests and exit the loop if all tests succeed.每次新尝试都必须再次尝试所有测试:使用带有单个scanf()实例的for循环来读取当前或新密码,执行测试并在所有测试成功时退出循环。 As a rule of thumb, avoid do / while loops as they tend to induce confusing and redundant code.根据经验,避免do / while循环,因为它们往往会导致混乱和冗余代码。

Here is a modified version:这是修改后的版本:

#include <ctype.h>
#include <stdio.h>
#include <string.h>

int get_new_password(char *output,              // destination array, longer than max_length
                     int min_length,            // minimum password length
                     int max_length,            // maximum password length
                     const char *special_chars, // set of special chars if any required
                     const char *current_pwd)   // current password if any
{
    char password[50];
    char newpassword[50];
    int has_letter, has_digit, has_special, len, c;

    if (current_pwd != NULL && *current_pwd != '\0') {
        for (;;) {
            printf("Please enter your current password: ");
            if (scanf("%49s", password) != 1)
                return -1;
            if (strcmp(current_pwd, password) != 0) {
                printf("Invalid password. Try again.\n");
                continue;
            }
            break;  // current password is correct.
        }
    }

    for (;;) {
        printf("Please enter your new password: ");
        if (scanf("%49s", newpassword) != 1)
            return -1;

        len = strlen(newpassword);
        if (len < min_length) {
            printf("The password must have at least %d characters.\n", min_length);
            continue;
        }
        if (len > max_length) {
            printf("The password must have at most %d characters.\n", max_length);
            continue;
        }
        has_letter = has_digit = has_special = 0;

        for (int i = 0; i < len; i++) {
            c = newpassword[i];
            if (isalpha((unsigned char)c)) {
                has_letter = 1;
            } else
            if (isdigit((unsigned char)c)) {
                has_digit = 1;
            } else
            if (special_chars && strchr(special_chars, c) != NULL) {
                has_special = 1;
            }
        }
        if (has_letter == 0) {
            printf("The password must have at least one letter.\n");
            continue;
        }
        if (has_digit == 0) {
            printf("The password must have at least one digit.\n");
            continue;
        }
        if (special_chars != NULL && has_special == 0) {
            printf("The password must have at least one of %s\n", special_chars);
            continue;
        }
        break;  // new password passed all tests
    }
    strcpy(output, newpassword);
    return 0;
}

int main() {
    char mypassword[] = "A1$B2C";
    char newpassword[21];

    if (get_new_password(newpassword, 6, 20, "@#$%", mypassword)) {
        printf("Invalid input, aborted.\n");
        return 1;
    } else {
        printf("New password: %s\n", newpassword);
        return 0;
    }
}

I suggest you would break your validation into a separate function, makes the code more readable.我建议您将验证分解为单独的 function,使代码更具可读性。 Below is a suggestion, which also lets you easily print out which validation criteria fails in case of an invalid password.下面是一个建议,它还可以让您轻松打印出在密码无效的情况下哪些验证标准失败。

#define VALIDATE_OK 0
#define VALIDATE_TOO_SHORT (1 << 0)
#define VALIDATE_TOO_LONG (1 << 1)
#define VALIDATE_LETTER (1 << 2)
#define VALIDATE_DIGIT (1 << 3)
#define VALIDATE_SPECIAL_CHAR (1 << 4)

#define MIN_LENGTH 6
#define MAX_LENGTH 20

static int validate(const char *str) {
    const char special_chars[] = { '@', '#', '$', '%' };
    size_t len = strlen(str);
    int ret = VALIDATE_TOO_SHORT|VALIDATE_TOO_LONG|VALIDATE_LETTER|
        VALIDATE_DIGIT|VALIDATE_SPECIAL_CHAR;

    if (len >= MIN_LENGTH) ret &= ~VALIDATE_TOO_SHORT;
    if (len <= MAX_LENGTH) ret &= ~VALIDATE_TOO_LONG;
    for (size_t i = 0; i < len; i++) {
        if (isalpha((unsigned char)str[i])) {
             ret &= ~VALIDATE_LETTER;
             continue;
        }
        if (isdigit((unsigned char)str[i])) {
            ret &= ~VALIDATE_DIGIT;
            continue;
        }
        for (size_t j = 0; j < sizeof special_chars; j++) {
            if (str[i] == special_chars[j]) {
                ret &= ~VALIDATE_SPECIAL_CHAR;
                break;
            }
        }
    }
    return ret;
}

EDIT: Now properly returns all missing criteria.编辑:现在正确返回所有缺失的条件。

Use strchr ( https://www.cplusplus.com/reference/cstring/strchr/ ).使用 strchr ( https://www.cplusplus.com/reference/cstring/strchr/ )。 If the char wasn't found, it returns a null pointer.如果未找到 char,则返回 null 指针。

Edit: Another solution would be to use a for loop:编辑:另一个解决方案是使用 for 循环:

size_t len=strlen(newpassword);
if(len<3||len>20){
  //Invalid length
}
int hasDigit=0;
int hasSpecial=0;
int hasLetter=0;
for(size_t i=0;i<len;i++) {
  char c=newpassword[i];
  if(isdigit(c)){
    hasDigit=1;
  }else if(c=='@'||c=='#'||c=='$'||c=='%'){
    hasSpecial=1;
  }else{
    hasLetter=1;
  }
  ...
}
if(hasDigit&&hasSpecial&&hasLetter){
  //Valid password
}

Edit 2:编辑2:

if (isalpha(newpassword[i]) != 0){
        counter3 += 1;
    }

I think this shouldn't be there and simply in the else clause:我认为这不应该存在,而只是在 else 子句中:

else{
   counter3 += 1;
}

(This will be too long for a comment) Lets start at the beginning: (这对于评论来说太长了)让我们从头开始:

  1. You ask the user for the current password.您向用户询问当前密码。 1.1 Repeat, if it's the wrong one. 1.1 重复,如果是错误的。
  2. You ask for the new one.你要新的。
  3. You go about every char in the new password.你 go 关于新密码中的每个字符。
    3.1 If it is a digit, add 1 to counter 2 3.1 如果是数字,计数器2加1
    3.2 If it is a special char, add 1 to counter 1 3.2 如果是特殊字符,计数器1加1
    3.3 Here you should simply add 1 to counter1. 3.3 这里你应该简单地给 counter1 加 1。
    4.After that you enter the while(check == 0) -Loop 4.之后你进入while(check == 0) -Loop
    4.1 You enter the while(counter1 == 0 || counter2 == 0 || counter3 == 0) loop, these will be endless, as it is impossible to changle one of the counter variables. 4.1 您进入while(counter1 == 0 || counter2 == 0 || counter3 == 0)循环,这些将是无止境的,因为不可能改变计数器变量之一。
    4.2 Everything else is dead code, because it can't be accessed. 4.2 其他都是死代码,因为无法访问。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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