题目描述
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@!”包含四个特殊字符之外的字符“^”,不合规。
一、题目分析
题目要求检测一组密码是否合规,合规需满足三个条件:
- 字符合法:仅由小写字母(a-z)、大写字母(A-Z)、数字(0-9)及特殊字符
!@#$组成; - 长度合法:长度在 6~12 之间(包含 6 和 12);
- 组合合法:大写字母、小写字母、数字中至少包含两种,且至少包含一个
!@#$中的特殊字符。
输入为用逗号分隔的多个密码字符串,输出所有合规的密码,按输入顺序排列。
二、核心思路
- 分割输入:将输入的整行字符串按逗号分割为单个密码;
- 逐个检测:对每个密码,依次检查是否满足字符合法、长度合法、组合合法三个条件;
- 输出合规密码:将符合所有条件的密码按输入顺序输出。
三、代码实现步骤详解
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;
}
四、关键逻辑解析
-
字符合法性判断:利用
cctype库的islower(小写)、isupper(大写)、isdigit(数字)函数,结合特殊字符的直接判断,确保密码中没有非法字符(如样例中的&和^)。 -
组合条件验证:通过四个布尔变量标记各类字符的存在,计算 “大写 / 小写 / 数字” 三类中至少两种(
typeCount ≥ 2),且必须有特殊字符(hasSpecial = true),满足题目第三点要求。 -
字符串分割:用
string::find查找逗号位置,substr提取子串,erase移除已处理部分,确保所有密码(包括最后一个无逗号的)都被检测。
五、示例测试解析
输入样例:
plaintext
seHJ12!@,sjdkffH$123,sdf!@&12HDHa!,123&^YUhg@!
分割后的四个密码及检测结果:
-
seHJ12!@:- 长度 8(6~12)→ 合法;
- 字符均为小写(s,e)、大写(H,J)、数字(1,2)、特殊字符(!@)→ 合法;
- 包含小写、大写、数字(3 种≥2),且有特殊字符→ 组合合法。输出。
-
sjdkffH$123:- 长度 11(6~12)→ 合法;
- 字符均为小写(s,j 等)、大写(H)、数字(1,2,3)、特殊字符($)→ 合法;
- 包含小写、大写、数字(3 种≥2),且有特殊字符→ 组合合法。输出。
-
sdf!@&12HDHa!:- 长度 13(>12)→ 不合规。不输出。
-
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;
}
1357

被折叠的 条评论
为什么被折叠?



