如何使用C++实现数据脱敏的自动列选择功能 替代硬编码方案
解决方案
核心改造思路
你当前的问题是脱敏规则与业务逻辑强耦合,通过规则配置化的思路剥离硬编码逻辑后,无需修改核心代码即可新增/调整事件的脱敏规则:
- 抽离所有事件的脱敏规则为独立配置项,与执行逻辑完全解耦
- 复用重复的脱敏处理逻辑,消除冗余代码
- 新增事件场景仅需补充配置项,无需修改核心执行代码
改造后完整代码
#include <iostream> #include <string> #include <vector> #include <fstream> #include <sstream> #include <ctime> #include <unordered_set> #include <stdexcept> using namespace std; // 读取CSV文件 vector<vector<string>> read_csv(const string& filename){ ifstream input_file(filename); vector<string> row_items; vector<vector<string>> result; if (!input_file.is_open()) throw runtime_error("无法打开文件"); string line, item; while(getline(input_file, line)){ row_items.clear(); stringstream ss(line); while(getline(ss, item, ',')){ row_items.push_back(item); } result.push_back(row_items); } input_file.close(); return result; } // 写入CSV文件 void write_csv(const string& filename, const vector<vector<string>>& dataset){ ofstream output_file(filename); for (size_t rows = 0; rows < dataset.size(); rows++){ for(size_t cols = 0; cols < dataset[rows].size(); cols++){ output_file << dataset[rows][cols]; if (cols != dataset[rows].size() - 1) output_file << ","; } output_file << "\n"; } output_file.close(); cout << "\n文件已保存为CSV格式!\n"; } // 字符串脱敏逻辑,将字符替换为x,保留空格和小数点 string mask_string(const string& str_value){ string new_str; new_str.reserve(str_value.size()); for (char c : str_value){ if (isspace(c)) new_str += ' '; else if (c == '.') new_str += '.'; else new_str += 'x'; } return new_str; } // 脱敏规则结构体,存储每个事件的脱敏配置 struct MaskRule { string event_name; unordered_set<int> keep_cols; // 保留明文无需脱敏的列 unordered_set<int> partial_mask_cols; // 需要部分脱敏的列 int partial_start_pos = 4; // 部分脱敏的起始下标 }; // 统一脱敏执行逻辑 void mask_column(vector<vector<string>>& dataset, int event) { // 所有事件的脱敏配置,新增事件仅需在此添加配置即可 vector<MaskRule> all_rules = { {"占位", {}, {}, 4}, // 下标0占位,事件id从1开始 // 事件1:能耗事件 {"能耗事件", {0,6,7,8,10,13,14,15,17,22}, {1,3,9,12,16}, 4}, // 事件2:非技术损耗事件 {"非技术损耗事件", {0,6,7,8,10,13,14,15,18,19,20,21}, {1,3,9,12,16}, 4}, // 事件3:用电模式事件 {"用电模式事件", {0,6,7,8,10,13,14,15,17,22}, {1,3,9,12,16}, 4}, // 事件4:全量PII脱敏 {"全量PII脱敏", {0,6,7,8,10,13,14,15,17,18,19,20,21,22}, {1,3,9,12,16}, 4} }; // 校验事件id合法性 if (event < 1 || event >= all_rules.size()) { throw runtime_error("输入的事件id不存在"); } const MaskRule& rule = all_rules[event]; // 遍历数据行,跳过表头行 for (size_t rows = 1; rows < dataset.size(); rows++) { for (size_t cols = 0; cols < dataset[rows].size(); cols++) { int col_id = static_cast<int>(cols); // 保留列无需处理 if (rule.keep_cols.count(col_id)) { continue; } // 部分脱敏列处理 if (rule.partial_mask_cols.count(col_id)) { string& val = dataset[rows][cols]; if (val.size() > rule.partial_start_pos) { val.replace(rule.partial_start_pos, val.size() - rule.partial_start_pos, mask_string(val.substr(rule.partial_start_pos))); } } // 全量脱敏列处理 else { dataset[rows][cols] = mask_string(dataset[rows][cols]); } } } } int main(){ // 显示当前日期时间 time_t now = time(0); char* date_time = ctime(&now); cout << "当前日期时间: " << date_time; cout << "\n欢迎使用IDSA程序\n"; cout << "~我们为您保护客户数据~\n"; // 读取CSV文件 int event; vector<vector<string>> dataset = read_csv("originaldataset.csv"); // 用户选择事件 cout << "\n可选择的事件类型:\n\n"; cout << "1. 能耗事件\n"; cout << "2. 非技术损耗事件\n"; cout << "3. 用电模式事件\n"; cout << "4. 全量PII脱敏"; cout << "\n\n请输入事件编号: "; cin >> event; try { mask_column(dataset, event); write_csv("masked_originaldataset.csv", dataset); } catch (const exception& e) { cout << "处理出错: " << e.what() << endl; return 1; } return 0; }
内容的提问来源于stack exchange,提问作者star
相关产品推荐
相关产品推荐

