【问题标题】:How to verify a password to have at least one uppercase, lowercase and number in C?如何验证密码在C中至少有一个大写,小写和数字?
【发布时间】:2013-11-08 19:34:32
【问题描述】:

我应该怎么做才能让它一直循环,直到它至少有一个大写、小写和数字?

我卡住了,真的卡住了……

char password[100][15];
i=1;
     printf("Password [3..10]: ");
        gets(password[i]);
        while (strlen(password[i])>10 || strlen(password[i])<3 || ) {   
        do{
        printf("  Password must contain at least 1 uppercase, 1 lowercase, and 1 number\nPassword [3..10]: ");
        gets(password[i]);
        } while (strlen(password[i])>10 || strlen(password[i])<3 );

【问题讨论】:

  • 这是我第一次看到 while/do/while 模式。你能解决这个问题吗,因为它没有多大意义。
  • 另外,避免使用gets。强烈不推荐。这很危险(容易受到攻击)。 (刚开始学习的时候可能还可以,但是千万不要养成使用它的习惯。:))

标签: c passwords uppercase lowercase


【解决方案1】:

使用这个正则表达式:

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$

它说你必须至少有一个小写字符,一个大写字符和至少一个数字加上它比ctype方法少打字。

例子:

#include <regex.h>

int main (int argc, char *argv[])
{
    regex_t regex;
    int regexResult = regcomp(&regex, "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$", 0);
    regexResult = regexec(&regex, passwordVariableHere, 0, NULL, 0);

    if (!regex)
    {
        // Match
    }
}

【讨论】:

  • 这可能是也可能不是很好,但它不适合“easy C”,最重要的是,它不适合用户体验级别,这可以通过 Q 的类型和代码
  • @ShinTakezou 你是对的,但我现在有一个关于如何使用它的清晰示例,所以现在应该很容易理解。
  • 这对我来说似乎有点矫枉过正,使用ctype.h 函数的解决方案更便携,更易于阅读。正则表达式在“只写”语法方面享有盛誉。
【解决方案2】:

这应该可行:

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

int is_legal(char *p) {
  int number = 0, lower = 0, upper = 0, length = 0;
  for( ; *p; p++) {
      number += isdigit(*p);   
      lower  += islower(*p);     
      upper  += isupper(*p);
      length++;
  }
  return number > 0 && lower > 0 && upper > 0  && length > 3 && length < 10;
}

char *my_gets(char *buf, int bufsize, FILE *file) {
    if(fgets(buf, bufsize, file) == 0) {
        return 0;
    }
    int n = strlen(buf);
    if(buf[n-1] == '\n') buf[n-1] = 0;
    return buf;
}

int get_password(char *buf, int bufsize, FILE *file) {
    printf("Password [3..10]: ");
    if(my_gets(buf, bufsize, file) == 0) {
        return -1;
    }
    while(is_legal(buf) == 0) {
       printf("  Password must contain at least 1 uppercase, 1 lowercase, and 1    umber\nPassword [3..10]: ");
       if(my_gets(buf, bufsize, file) == 0) {
           return -1;
       }
    }
    return 0;
}

int main(void) {
    char password[100][15];
    int i = 0;
    if(get_password(password[i], sizeof(password[i]), stdin) != 0) {
        fprintf(stderr, "Error getting password\n");
        exit(1);
   }
   return 0;
}

【讨论】:

  • 在给出有效输入之前不会处理循环。不过不错:-)
  • 我知道,但考虑到 OPs 问题的质量,或许也可以展示一下如何做到这一点 :-)
  • @anishsane,你有什么建议?
  • fgets。请注意, fgets 在 NULL 终止之前将 \n 添加到字符串中。您可能需要删除它...
【解决方案3】:

查看ctype.h 标头。检查密码的每个字符,直到满足所有条件(大写、小写、数字)。如果您到达密码字符串的末尾并且任何条件不满足,则密码错误。

【讨论】:

    【解决方案4】:

    也许这是一种检查 ASCII 表中字符位置的简单方法。您可以将所有字符检查为 65 到 90 之间的数字,用于大写字符,同样用于小写。

    对于数字,您可以使用标准 c 库中的 atoi() 函数。

    或者另一种可能性是使用 ctype.h 中的函数:islower()、isupper() 或 isdigit()。

    【讨论】:

    • 在我看来,在这种情况下使用 atoi 没有多大意义。
    • 另外,您不需要知道 ascii 值。您可以简单地与A 进行比较,而不是650x41
    • @SirDarius 我认为 atoi("4") = 4,因此您可以确定字符是否为数字。目前我注意到,在这种情况下,零不会被检测为数字。更好的解决方案是上面的第二个。
    • 不! atoi("#")==0,一个数字,但 '#' 不是一个数字。
    • 我的第一条评论中有一个错误:将A 阅读为'A'
    【解决方案5】:

    我不太明白您为什么要使用一组 15 个字符长的密码,但我想您的标准仅指其中一个密码,而不是其他密码:您想检查密码是否有要求被视为“好”密码;这是我的理解。那么……

    函数gets 相当不安全。避免使用它。

    这个想法是要求输入密码,检查它并在它不符合您的标准时循环。当然,没有一种方法可以做到这一点。

    // include files for I/O funcs
    #include <stdio.h>
    
    for(;;)
    {
       printf("insert pwd: ");
       gets(buffer); // argh I've said: don't use this
       if ( !pass_criteria(buffer) ) {
           printf("criteria are ....\n");
       } else break;
    }
    

    那么 pass_criteria 可能是这样的

    // include files for strlen and is* funcs
    #include <ctype.h>
    #include <string.h>
    
    int pass_criteria(const char *buf)
    {
        int upcount, lowcount, numcount;
    
        if (strlen(buf) < minimum_pass_len ||
            strlen(buf) > max_pass_len) return 0; // 0 being false
    
        for (int i = 0; i < strlen(buf); ++i) {
           if (isdigit(buf[i]) numcount++;
           if (isupper(buf[i]) upcount++;
           if (islower(buf[i]) lowcount++;
        }
        return numcount > 0 && upcount > 0 && lowcount > 0;
    }
    

    更改标准很容易,例如如果您想要至少 2 个数字(数字),请输入 numcount &gt; 1 等等。

    而不是得到

    获取对于缓冲区溢出是危险的。尝试使用例如fget 是这样的:

       fgets(buffer, buffer_size, stdin);
    

    其中buffer_size 是缓冲区的大小(在您的情况下为15,但避免使用文字常量;更喜欢正确的#define 或使用sizeof,例如sizeof (password[0])。另请注意,fgets 不会丢弃最后一个换行符。

    【讨论】:

      猜你喜欢
      • 2018-01-23
      • 2015-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-07
      • 1970-01-01
      • 1970-01-01
      • 2021-02-18
      相关资源
      最近更新 更多