密码合规检测

题目描述

4010:【GESP2306三级】密码合规检测


时间限制: 1000 ms         内存限制: 65536 KB
提交数:3127    通过数: 1187

【题目描述】

网站注册需要有用户名和密码,编写程序以检查用户输入密码的有效性。合规的密码应满足以下要求:

1、只能由 a−za−z 之间 2626 个小写字母、A−ZA−Z 之间 2626 个大写字母、0−90−9 之间1010个数字以及!@#$四个特殊字符构成。

2、密码最短长度:66 个字符,密码最大长度:1212 个字符。

3、大写字母、小写字母和数字必须至少有其中两种,以及至少有四个特殊字符中的一个。

【输入】

输入一行不含空格的字符串。约定长度不超过 100100。该字符串被英文逗号分隔为多段,作为多组被检测密码。

【输出】

输出若干行,每行输出一组合规的密码。

输出顺序以输入先后为序,即先输入则先输出。

【输入样例】

seHJ12!@,sjdkffH$123,sdf!@&12HDHa!,123&^YUhg@!

【输出样例】

seHJ12!@
sjdkffH$123

【提示】

【样例解释 1】

输入被英文逗号分为了四组被检测密码:“seHJ12!@”、“sjdkffH$123”、“sdf!@&12HDHa!”、“123&^YUhg@!”。其中,“sdf!@&12HDHa!”长度超过12个字符,不合规;“123&^YUhg@!”包含四个特殊字符之外的字符“^”,不合规。

一、题目分析

题目要求检测一组密码是否合规,合规需满足三个条件:

  1. 字符合法:仅由小写字母(a-z)、大写字母(A-Z)、数字(0-9)及特殊字符!@#$组成;
  2. 长度合法:长度在 6~12 之间(包含 6 和 12);
  3. 组合合法:大写字母、小写字母、数字中至少包含两种,且至少包含一个!@#$中的特殊字符。

输入为用逗号分隔的多个密码字符串,输出所有合规的密码,按输入顺序排列。

二、核心思路

  1. 分割输入:将输入的整行字符串按逗号分割为单个密码;
  2. 逐个检测:对每个密码,依次检查是否满足字符合法、长度合法、组合合法三个条件;
  3. 输出合规密码:将符合所有条件的密码按输入顺序输出。

三、代码实现步骤详解

1. 引入头文件与命名空间

cpp

运行

#include <iostream>   // 输入输出流
#include <string>     // 字符串处理
#include <cctype>     // 字符类型判断函数(islower、isupper等)
using namespace std;

2. 定义密码检测函数 isValidPassword

该函数接收一个字符串(密码),返回true(合规)或false(不合规),分三步检测:

步骤 1:检查长度是否合法

cpp

运行

if (pwd.size() < 6 || pwd.size() > 12) {
    return false;  // 长度小于6或大于12,不合规
}
步骤 2:检查所有字符是否合法

遍历密码中的每个字符,判断是否为允许的类型(小写、大写、数字、!@#$):

cpp

运行

for (char c : pwd) {
    // 若字符不是小写、大写、数字,也不是!@#$,则不合规
    if (!islower(c) && !isupper(c) && !isdigit(c) && c != '!' && c != '@' && c != '#' && c != '$') {
        return false;
    }
}
步骤 3:检查组合是否合法

统计密码中是否包含小写、大写、数字、特殊字符,再验证组合条件:

cpp

运行

// 标记是否存在小写、大写、数字、特殊字符
bool hasLower = false, hasUpper = false, hasDigit = false, hasSpecial = false;

for (char c : pwd) {
    if (islower(c)) hasLower = true;       // 检测到小写字母
    else if (isupper(c)) hasUpper = true;  // 检测到大写字母
    else if (isdigit(c)) hasDigit = true;  // 检测到数字
    else if (c == '!' || c == '@' || c == '#' || c == '$') hasSpecial = true;  // 检测到特殊字符
}

// 计算大写、小写、数字中至少包含几种(需≥2种),且必须有特殊字符
int typeCount = (hasLower ? 1 : 0) + (hasUpper ? 1 : 0) + (hasDigit ? 1 : 0);
return (typeCount >= 2) && hasSpecial;  // 组合合法则返回true

3. 主函数 main 处理输入与输出

步骤 1:读取整行输入

cpp

运行

string input;
getline(cin, input);  // 读取包含逗号分隔的所有密码
步骤 2:按逗号分割输入,逐个检测密码

cpp

运行

size_t pos = 0;       // 记录逗号位置
string token;         // 存储分割出的单个密码

// 循环分割字符串,直到找不到逗号
while ((pos = input.find(',')) != string::npos) {
    token = input.substr(0, pos);  // 提取从0到逗号位置的子串(当前密码)
    if (isValidPassword(token)) {  // 若合规,输出
        cout << token << endl;
    }
    input.erase(0, pos + 1);  // 移除已处理的密码和逗号,继续处理剩余部分
}

// 处理最后一个密码(输入中最后一个逗号后的部分)
if (isValidPassword(input)) {
    cout << input << endl;
}

四、关键逻辑解析

  1. 字符合法性判断:利用cctype库的islower(小写)、isupper(大写)、isdigit(数字)函数,结合特殊字符的直接判断,确保密码中没有非法字符(如样例中的&^)。

  2. 组合条件验证:通过四个布尔变量标记各类字符的存在,计算 “大写 / 小写 / 数字” 三类中至少两种(typeCount ≥ 2),且必须有特殊字符(hasSpecial = true),满足题目第三点要求。

  3. 字符串分割:用string::find查找逗号位置,substr提取子串,erase移除已处理部分,确保所有密码(包括最后一个无逗号的)都被检测。

五、示例测试解析

输入样例:

plaintext

seHJ12!@,sjdkffH$123,sdf!@&12HDHa!,123&^YUhg@!
分割后的四个密码及检测结果:
  1. seHJ12!@

    • 长度 8(6~12)→ 合法;
    • 字符均为小写(s,e)、大写(H,J)、数字(1,2)、特殊字符(!@)→ 合法;
    • 包含小写、大写、数字(3 种≥2),且有特殊字符→ 组合合法。输出
  2. sjdkffH$123

    • 长度 11(6~12)→ 合法;
    • 字符均为小写(s,j 等)、大写(H)、数字(1,2,3)、特殊字符($)→ 合法;
    • 包含小写、大写、数字(3 种≥2),且有特殊字符→ 组合合法。输出
  3. sdf!@&12HDHa!

    • 长度 13(>12)→ 不合规。不输出
  4. 123&^YUhg@!

    • 包含非法字符^→ 不合规。不输出

输出样例:

plaintext

seHJ12!@
sjdkffH$123

六、完整代码

cpp

运行

#include <iostream>
#include <string>
#include <cctype>

using namespace std;

bool isValidPassword(const string& pwd) {
    // 检查长度
    if (pwd.size() < 6 || pwd.size() > 12) {
        return false;
    }
    // 检查字符合法性
    for (char c : pwd) {
        if (!islower(c) && !isupper(c) && !isdigit(c) && c != '!' && c != '@' && c != '#' && c != '$') {
            return false;
        }
    }
    // 统计字符类型
    bool hasLower = false, hasUpper = false, hasDigit = false, hasSpecial = false;
    for (char c : pwd) {
        if (islower(c)) hasLower = true;
        else if (isupper(c)) hasUpper = true;
        else if (isdigit(c)) hasDigit = true;
        else if (c == '!' || c == '@' || c == '#' || c == '$') hasSpecial = true;
    }
    // 检查组合条件
    int typeCount = (hasLower ? 1 : 0) + (hasUpper ? 1 : 0) + (hasDigit ? 1 : 0);
    return (typeCount >= 2) && hasSpecial;
}

int main() {
    string input;
    getline(cin, input);
    
    size_t pos = 0;
    string token;
    while ((pos = input.find(',')) != string::npos) {
        token = input.substr(0, pos);
        if (isValidPassword(token)) {
            cout << token << endl;
        }
        input.erase(0, pos + 1);
    }
    if (isValidPassword(input)) {
        cout << input << endl;
    }
    
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值