|
|
|
|
@ -10,20 +10,20 @@
|
|
|
|
|
#include <cctype>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
|
|
// 安全处理用户名,移除或替换非法字符
|
|
|
|
|
// 安全处理用户名,移除或替换非法字符
|
|
|
|
|
std::string FileHandler::getSafeUsername(const std::string& username) {
|
|
|
|
|
std::string safeUsername;
|
|
|
|
|
for (char c : username) {
|
|
|
|
|
// 只允许字母、数字、下划线、连字符和点号
|
|
|
|
|
// 只允许字母、数字、下划线、连字符和点号
|
|
|
|
|
if (std::isalnum(c) || c == '_' || c == '-' || c == '.') {
|
|
|
|
|
safeUsername += c;
|
|
|
|
|
} else {
|
|
|
|
|
// 将其他字符替换为下划线
|
|
|
|
|
// 将其他字符替换为下划线
|
|
|
|
|
safeUsername += '_';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 确保用户名不为空
|
|
|
|
|
// 确保用户名不为空
|
|
|
|
|
if (safeUsername.empty()) {
|
|
|
|
|
safeUsername = "default_user";
|
|
|
|
|
}
|
|
|
|
|
@ -31,39 +31,39 @@ std::string FileHandler::getSafeUsername(const std::string& username) {
|
|
|
|
|
return safeUsername;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取用户目录路径
|
|
|
|
|
// 获取用户目录路径
|
|
|
|
|
std::string FileHandler::getUserPath(const std::string& username) {
|
|
|
|
|
return "papers/" + getSafeUsername(username);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建用户目录
|
|
|
|
|
// 创建用户目录
|
|
|
|
|
void FileHandler::createUserDir(const std::string& username) {
|
|
|
|
|
std::string userPath = getUserPath(username);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if (!fs::exists(userPath)) {
|
|
|
|
|
// 递归创建目录
|
|
|
|
|
// 递归创建目录
|
|
|
|
|
bool created = fs::create_directories(userPath);
|
|
|
|
|
if (!created) {
|
|
|
|
|
std::cerr << "警告: 无法创建用户目录: " << userPath << std::endl;
|
|
|
|
|
std::cerr << "警告: 无法创建用户目录: " << userPath << std::endl;
|
|
|
|
|
} else {
|
|
|
|
|
std::cout << "已创建用户目录: " << userPath << std::endl;
|
|
|
|
|
std::cout << "已创建用户目录: " << userPath << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (const fs::filesystem_error& e) {
|
|
|
|
|
std::cerr << "文件系统错误 - 创建目录失败: " << e.what() << std::endl;
|
|
|
|
|
// 尝试创建默认目录作为备用
|
|
|
|
|
std::cerr << "文件系统错误 - 创建目录失败: " << e.what() << std::endl;
|
|
|
|
|
// 尝试创建默认目录作为备用
|
|
|
|
|
try {
|
|
|
|
|
if (!fs::exists("papers/default_user")) {
|
|
|
|
|
fs::create_directories("papers/default_user");
|
|
|
|
|
}
|
|
|
|
|
} catch (...) {
|
|
|
|
|
std::cerr << "严重错误: 无法创建默认目录" << std::endl;
|
|
|
|
|
std::cerr << "严重错误: 无法创建默认目录" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 保存题目到文件
|
|
|
|
|
// 保存题目到文件
|
|
|
|
|
void FileHandler::saveQuestions(const std::string& username, const std::vector<std::string>& questions) {
|
|
|
|
|
try {
|
|
|
|
|
createUserDir(username);
|
|
|
|
|
@ -72,7 +72,7 @@ void FileHandler::saveQuestions(const std::string& username, const std::vector<s
|
|
|
|
|
|
|
|
|
|
std::ofstream file(fullPath);
|
|
|
|
|
if (!file.is_open()) {
|
|
|
|
|
std::cerr << "错误: 无法打开文件: " << fullPath << std::endl;
|
|
|
|
|
std::cerr << "错误: 无法打开文件: " << fullPath << std::endl;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -81,18 +81,18 @@ void FileHandler::saveQuestions(const std::string& username, const std::vector<s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
|
std::cout << "题目已保存到: " << fullPath << std::endl;
|
|
|
|
|
std::cout << "题目已保存到: " << fullPath << std::endl;
|
|
|
|
|
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
std::cerr << "保存问题时出错: " << e.what() << std::endl;
|
|
|
|
|
std::cerr << "保存问题时出错: " << e.what() << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 规范化题目字符串,移除空格等以便比较
|
|
|
|
|
// 规范化题目字符串,移除空格等以便比较
|
|
|
|
|
std::string FileHandler::normalizeQuestion(const std::string& question) {
|
|
|
|
|
std::string normalized = question;
|
|
|
|
|
|
|
|
|
|
// 移除所有空格
|
|
|
|
|
// 移除所有空格
|
|
|
|
|
normalized.erase(std::remove_if(normalized.begin(), normalized.end(),
|
|
|
|
|
[](unsigned char c) { return std::isspace(c); }),
|
|
|
|
|
normalized.end());
|
|
|
|
|
@ -100,7 +100,7 @@ std::string FileHandler::normalizeQuestion(const std::string& question) {
|
|
|
|
|
return normalized;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查题目是否重复
|
|
|
|
|
// 检查题目是否重复
|
|
|
|
|
bool FileHandler::isDuplicate(const std::string& username, const std::string& question) {
|
|
|
|
|
std::string userPath = getUserPath(username);
|
|
|
|
|
|
|
|
|
|
@ -119,13 +119,13 @@ bool FileHandler::isDuplicate(const std::string& username, const std::string& qu
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (const fs::filesystem_error& e) {
|
|
|
|
|
std::cerr << "文件系统错误 - 检查重复题目失败: " << e.what() << std::endl;
|
|
|
|
|
std::cerr << "文件系统错误 - 检查重复题目失败: " << e.what() << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查文件中是否包含特定题目
|
|
|
|
|
// 检查文件中是否包含特定题目
|
|
|
|
|
bool FileHandler::checkFile(const fs::path& path, const std::string& normalizedQuestion) {
|
|
|
|
|
try {
|
|
|
|
|
std::ifstream file(path);
|
|
|
|
|
@ -135,31 +135,31 @@ bool FileHandler::checkFile(const fs::path& path, const std::string& normalizedQ
|
|
|
|
|
|
|
|
|
|
std::string line;
|
|
|
|
|
while (std::getline(file, line)) {
|
|
|
|
|
// 跳过序号行(如 "1. ")
|
|
|
|
|
// 跳过序号行(如 "1. ")
|
|
|
|
|
if (line.empty() || (line.find('.') != std::string::npos &&
|
|
|
|
|
std::isdigit(line[0]) && line.size() > 2 && line[1] == '.')) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 规范化当前行并与题目比较
|
|
|
|
|
// 规范化当前行并与题目比较
|
|
|
|
|
std::string normalizedLine = normalizeQuestion(line);
|
|
|
|
|
if (normalizedLine == normalizedQuestion) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
|
std::cerr << "检查文件内容时出错: " << e.what() << std::endl;
|
|
|
|
|
std::cerr << "检查文件内容时出错: " << e.what() << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取时间戳字符串
|
|
|
|
|
// 获取时间戳字符串
|
|
|
|
|
std::string FileHandler::getTimestamp() {
|
|
|
|
|
auto now = std::chrono::system_clock::now();
|
|
|
|
|
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
|
|
|
|
|
|
|
|
|
|
// 使用线程安全的时间函数
|
|
|
|
|
// 使用线程安全的时间函数
|
|
|
|
|
std::tm local_time;
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
localtime_s(&local_time, &now_c);
|
|
|
|
|
|