• C++
  • [GESP202306 三级] 密码合规

  • @ 2025-7-14 20:18:38

B3843 [GESP202306 三级] 密码合规

题目描述

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

  1. 只能由 az\texttt a \sim \texttt z 之间 2626 个小写字母、AZ\texttt A \sim \texttt Z 之间 2626 个大写字母、090 \sim 9 之间 1010 个数字以及 !@#$ 四个特殊字符构成。

  2. 密码最短长度 :6:6 个字符,密码最大长度 :12:12 个字符。

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

输入格式

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

输出格式

输出若干行,每行输出一组合规的密码。输出顺序以输入先后为序,即先输入则先输出。

输入输出样例 #1

输入 #1

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

输出 #1

seHJ12!@
sjdkffH$123

说明/提示

【样例 1 解释】

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

2 条评论

  • @ 2025-7-14 20:20:04

    下面是优化变量名称后的C++密码合规检测程序学习笔记,变量名更直观,代码注释更详细,便于理解:

    C++密码合规检测程序学习笔记(优化版)

    一、程序目标

    编写程序检测密码是否合规,合规密码需满足3个条件(见题目描述)。程序需读取用逗号分隔的多个密码,逐个检测后输出所有合规的密码。

    二、优化后的代码(带详细注释)

    #include<iostream>
    #include<string>  // 注意:原代码漏了<string>头文件,这里补充,否则string操作可能报错
    using namespace std;
    
    // 函数功能:检查单个密码是否合规
    // 参数:待检测的密码字符串
    // 返回值:true(合规)/ false(不合规)
    bool isPasswordValid(string password) {
        // 1. 检查长度是否在6-12之间(条件2)
        int passwordLen = password.size();  // 获取密码长度
        if (passwordLen < 6 || passwordLen > 12) {
            return false;  // 长度不合格
        }
        
        // 2. 检查是否只包含允许的字符(条件1)
        int validCharCount = 0;  // 记录合法字符的数量
        for (int i = 0; i < passwordLen; i++) {
            char currentChar = password[i];  // 当前遍历的字符
            // 判断是否为小写字母
            if (currentChar >= 'a' && currentChar <= 'z') {
                validCharCount++;
            }
            // 判断是否为大写字母
            else if (currentChar >= 'A' && currentChar <= 'Z') {
                validCharCount++;
            }
            // 判断是否为数字
            else if (currentChar >= '0' && currentChar <= '9') {
                validCharCount++;
            }
            // 判断是否为允许的特殊字符(!@#$)
            else if (currentChar == '!' || currentChar == '@' || currentChar == '#' || currentChar == '$') {
                validCharCount++;
            }
            // 如果以上都不是,说明是非法字符,直接返回不合格
            else {
                return false;
            }
        }
        // 注意:上面的else已经处理了非法字符,这里其实可以省略这个判断,不过保留更稳妥
        if (validCharCount != passwordLen) {
            return false;
        }
        
        // 3. 检查字符类型是否满足要求(条件3)
        bool hasUpper = false;  // 是否包含大写字母
        bool hasLower = false;  // 是否包含小写字母
        bool hasDigit = false;  // 是否包含数字
        bool hasSpecial = false;  // 是否包含特殊字符
        
        // 遍历密码,标记各类字符是否存在
        for (int i = 0; i < passwordLen; i++) {
            char currentChar = password[i];
            if (currentChar >= 'A' && currentChar <= 'Z') {
                hasUpper = true;  // 标记有大写字母
            } else if (currentChar >= 'a' && currentChar <= 'z') {
                hasLower = true;  // 标记有小写字母
            } else if (currentChar >= '0' && currentChar <= '9') {
                hasDigit = true;  // 标记有数字
            } else {
                hasSpecial = true;  // 能走到这一步,说明是!@#$中的一个
            }
        }
        
        // 检查是否满足:大写/小写/数字至少有两种,且至少有一个特殊字符
        int letterOrDigitType = 0;  // 记录大写/小写/数字的类型数量
        if (hasUpper) letterOrDigitType++;
        if (hasLower) letterOrDigitType++;
        if (hasDigit) letterOrDigitType++;
        
        if (letterOrDigitType < 2) {  // 不足两种类型
            return false;
        }
        if (!hasSpecial) {  // 没有特殊字符
            return false;
        }
        
        // 所有条件都满足,返回合规
        return true;
    }
    
    int main() {
        string inputStr;  // 存储输入的整行字符串(多个密码用逗号分隔)
        cin >> inputStr;  // 读取输入
        
        // 在输入末尾加一个逗号,方便统一处理最后一个密码(避免单独判断边界)
        inputStr += ",";
        
        string passwords[200];  // 存储分割后的所有密码
        int passwordCount = 0;  // 记录密码的总数量
        int inputLen = inputStr.size();  // 输入字符串的长度
        int startIndex = 0;  // 记录当前密码在输入字符串中的起始位置
        
        // 分割输入字符串,提取每个密码(按逗号分割)
        for (int i = 0; i < inputLen; i++) {
            if (inputStr[i] == ',') {  // 遇到逗号,说明前面是一个完整的密码
                passwordCount++;  // 密码数量加1
                // 提取从startIndex到i-1的子字符串(即当前密码)
                // substr(起始位置, 长度):长度 = 结束位置 - 起始位置
                passwords[passwordCount] = inputStr.substr(startIndex, i - startIndex);
                startIndex = i + 1;  // 更新下一个密码的起始位置
            }
        }
        
        // 逐个检查密码是否合规,合规则输出
        for (int i = 1; i <= passwordCount; i++) {
            if (isPasswordValid(passwords[i])) {  // 调用检查函数
                cout << passwords[i] << endl;
            }
        }
        
        return 0;
    }
    

    三、变量名优化说明

    原代码的变量名较为简略(如cntstra/b/c/d),优化后更直观:

    • cntvalidCharCount(合法字符计数)、passwordCount(密码总数)
    • strpassword(单个密码)、inputStr(输入字符串)
    • a/b/c/dhasUpper(有大写字母)、hasLower(有小写字母)、hasDigit(有数字)、hasSpecial(有特殊字符)
    • lenpasswordLen(密码长度)、inputLen(输入字符串长度)
    • startstartIndex(起始索引)

    优化后的变量名能直接反映变量的含义,减少理解成本。

    四、核心逻辑拆解

    1. 输入处理

      • 读取整行输入,通过在末尾加逗号,统一处理所有密码的分割(无需单独判断最后一个密码)
      • substr函数提取子字符串,实现按逗号分割密码
    2. 合规检查(isPasswordValid函数)

      • 长度检查:先判断密码长度是否在6-12之间,不满足则直接返回不合格
      • 字符合法性检查:遍历每个字符,若存在不允许的字符(如^&等),返回不合格
      • 类型检查:通过4个布尔变量标记是否存在大写/小写/数字/特殊字符,最终判断是否满足“至少两种字母/数字 + 至少一个特殊字符”

    五、关键知识点

    1. 字符串操作

      • size():获取字符串长度(如password.size()
      • substr(pos, len):提取子字符串(从pos开始,长度为len
      • 字符遍历:通过for循环逐个访问password[i]
    2. 布尔变量的应用

      • hasXXX系列布尔变量标记“是否存在某类字符”,避免重复判断,逻辑更清晰
      • 示例:hasUpper = true表示密码中存在大写字母
    3. 函数封装

      • 将密码检查逻辑封装到isPasswordValid函数中,使主函数更简洁,代码可复用

    六、测试案例分析(输入样例)

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

    • 分割后得到4个密码,逐个检查:
      1. seHJ12!@:长度8(合规),含小写、大写、数字、!@(合法字符),满足“3种字母/数字 + 特殊字符”→ 合规
      2. sjdkffH$123:长度11(合规),含小写、大写、数字、$→ 合规
      3. sdf!@&12HDHa!:长度14(超过12)→ 不合规
      4. 123&^YUhg@!:含非法字符^→ 不合规

    输出:前两个合规的密码

    七、常见问题

    1. 头文件遗漏:使用string类需包含<string>头文件,否则可能编译报错
    2. 边界处理:输入末尾不加逗号可能导致最后一个密码无法正确分割,加逗号是简化逻辑的技巧
    3. 字符判断顺序:特殊字符判断需放在最后(因为字母/数字的判断范围更明确)

    通过这个程序,我们可以掌握字符串处理、函数封装、条件判断等基础知识点,同时学习如何通过清晰的变量名和逻辑拆分提高代码可读性。

    • @ 2025-7-14 20:18:46

      下面是一份关于密码合规检测程序的C++学习笔记教程,包含详细注释和分步解释:

      C++密码合规检测程序学习笔记

      一、题目分析

      网站注册时,密码需要满足以下条件:

      1. 只能包含小写字母(a-z)、大写字母(A-Z)、数字(0-9)和特殊字符(!@#$)
      2. 长度要求:6-12个字符
      3. 必须包含至少两种类型的字符(大写、小写、数字)和至少一个特殊字符

      二、程序设计思路

      程序需要完成以下工作:

      1. 读取输入字符串并分割为多个密码
      2. 检查每个密码是否满足所有条件
      3. 输出符合条件的密码

      三、代码实现与详细注释

      #include<iostream>
      #include<string>
      using namespace std;
      
      // 检查密码是否合规的函数
      bool check(string str) {
          int len = str.size();
          
          // 条件2:检查密码长度是否在6-12个字符之间
          if (len < 6 || len > 12) {
              return false;
          }
          
          // 条件1:检查所有字符是否都属于允许的类型
          int cnt = 0;
          for (int i = 0; i < len; i++) {
              if ('a' <= str[i] && str[i] <= 'z') {
                  cnt += 1;  // 小写字母计数
              } else if ('A' <= str[i] && str[i] <= 'Z') {
                  cnt += 1;  // 大写字母计数
              } else if ('0' <= str[i] && str[i] <= '9') {
                  cnt += 1;  // 数字计数
              } else if (str[i] == '!' || str[i] == '@' || str[i] == '#' || str[i] == '$') {
                  cnt += 1;  // 特殊字符计数
              }
          }
          // 如果计数不等于字符串长度,说明有非法字符
          if (cnt != len) {
              return false;
          }
          
          // 条件3:检查是否包含至少两种类型的字符和至少一个特殊字符
          int a = 0, b = 0, c = 0, d = 0;
          for (int i = 0; i < len; i++) {
              if ('A' <= str[i] && str[i] <= 'Z') {
                  a = 1;  // 标记是否有大写字母
              }
              if ('a' <= str[i] && str[i] <= 'z') {
                  b = 1;  // 标记是否有小写字母
              }
              if ('0' <= str[i] && str[i] <= '9') {
                  c = 1;  // 标记是否有数字
              }
              if (str[i] == '!' || str[i] == '@' || str[i] == '#' || str[i] == '$') {
                  d = 1;  // 标记是否有特殊字符
              }
          }
          // 检查是否有至少两种字符类型
          if (a + b + c < 2) {
              return false;
          }
          // 检查是否有特殊字符
          if (d == 0) {
              return false;
          }
          
          return true;  // 所有条件都满足,返回真
      }
      
      int main() {
          string str;
          cin >> str;  // 读取输入字符串
          
          // 为了便于处理,在字符串末尾添加一个逗号
          str += ",";
          
          string words[200];  // 存储分割后的密码
          int cnt = 0;        // 记录密码数量
          int len = str.size();
          int start = 0;      // 记录当前密码的起始位置
          
          // 分割字符串,提取每个密码
          for (int i = 0; i < len; i++) {
              if (str[i] == ',') {
                  cnt += 1;  // 密码数量加1
                  // 提取从start到i的子字符串作为一个密码
                  words[cnt] = str.substr(start, i - start);
                  start = i + 1;  // 更新下一个密码的起始位置
              }
          }
          
          // 检查并输出每个合规的密码
          for (int i = 1; i <= cnt; i++) {
              if (check(words[i]) == true) {
                  cout << words[i] << endl;
              }
          }
          
          return 0;
      }
      

      四、核心知识点详解

      1. 字符串处理

        • str.size():获取字符串长度
        • str.substr(start, length):提取子字符串
        • 字符串遍历:使用for循环逐个访问字符
      2. 条件判断

        • 字符范围判断:'a' <= str[i] && str[i] <= 'z'
        • 逻辑组合判断:使用多个if-else和逻辑运算符
      3. 标记变量的使用

        • 使用a, b, c, d四个标记变量记录是否存在不同类型的字符
        • 通过标记变量的累加和判断是否满足条件
      4. 字符串分割技巧

        • 在字符串末尾添加分隔符简化处理
        • 使用substr函数提取子字符串

      五、测试与验证

      对于输入样例:seHJ12!@,sjdkffH$123,sdf!@&12HDHa!,123&^YUhg@! 程序会依次检查每个密码:

      • seHJ12!@:长度8,包含大写、小写、数字和特殊字符,符合条件
      • sjdkffH$123:长度11,包含小写、大写、数字和特殊字符,符合条件
      • sdf!@&12HDHa!:长度14,超过最大长度,不符合条件
      • 123&^YUhg@!:包含非法字符^,不符合条件

      因此输出结果为:

      seHJ12!@
      sjdkffH$123
      

      六、常见错误与注意事项

      1. 字符范围判断时要注意大小写和边界值
      2. 字符串分割时,处理最后一个子字符串的边界情况
      3. 标记变量的初始化和更新逻辑要清晰
      4. 注意字符串长度的有效范围检查

      通过这个程序,我们学习了如何处理字符串、实现复杂条件判断以及使用标记变量来简化逻辑判断。这些技巧在日常编程中非常实用。

      • 1