QT解析文本框数据——详解
上集回顾:QT解析文本框数据——概述
一、代码实现细节
1. 数据结构与变量
QMap<int, QList<QPair<int, int>>> businessData;
QMap<int, int> weights;
businessData
:键为业务ID,值为时间点-工作量对的列表weights
:业务ID到权重值的映射- 使用
QMap
而非QHash
:保持插入顺序,适合需要有序遍历的场景
2. 业务数据解析流程
QRegularExpression businessRegExp(R"((\d+):([^;]+);)");
- 正则表达式分解:
(\d+)
:捕获至少1个数字作为业务ID:([^;]+);
:捕获冒号后分号前的任意非分号字符作为业务数据
- 输入示例:
1:10-20,30-40;2:50-60;
- 解析结果:
- 业务ID=1,数据=“10-20,30-40”
- 业务ID=2,数据=“50-60”
3. 时间-工作量对解析
QRegularExpression timeValueRegExp(R"((\d+)-(\d+))");
- 输入示例:
10-20,30-40
- 处理逻辑:
- 按逗号分割字符串得到
["10-20", "30-40"]
- 对每个子串匹配正则表达式,提取时间点和工作量
- 存入
timeValues
列表
- 按逗号分割字符串得到
4. 权重数据解析
QRegularExpression weightRegExp(R"((\d+):(\d+);)");
- 输入示例:
1:5;2:3;
- 处理逻辑:
- 提取业务ID和对应权重值
- 存入
weights
映射
5. 数据验证与默认值处理
if (businessData.isEmpty()) {QMessageBox::warning(this, "错误", "未解析到有效业务数据");return false;
}for (int businessId : businessData.keys()) {if (!weights.contains(businessId)) {weights[businessId] = 1;}
}
- 验证逻辑:
- 确保至少有一条有效业务数据
- 为未设置权重的业务补充默认权重1
二、潜在问题与风险
1. 正则表达式匹配风险
- 部分匹配问题:
- 输入
1:10-20;30-40;
会被错误解析为:- 业务ID=1,数据=“10-20”
- 业务ID=30,数据=“40”
- 输入
- 边缘情况处理:
- 输入
1:10-20
(缺少结尾分号)会导致整行数据丢失
- 输入
2. 数据转换问题
int businessId = businessMatch.captured(1).toInt();
toInt()
行为:- 输入"abc" → 返回0,不报错
- 输入"123abc" → 返回123,忽略后续字符
- 可能导致:
- 业务ID冲突(多个业务被映射到ID=0)
- 数据解析异常但无明确错误提示
3. 数据完整性问题
- 重复业务ID:
- 输入
1:10-20;1:30-40;
会导致后一个数据覆盖前一个
- 输入
- 权重不匹配:
- 权重文本中的业务ID在业务数据中不存在时,该权重值被忽略
- 无警告或错误提示
4. 性能问题
- 嵌套循环开销:
- 遍历
businessData.keys()
时会生成临时列表 - 对大型数据集有性能影响
- 遍历
三、优化建议
1. 增强错误处理
// 示例:添加输入验证
bool isValidBusinessId(const QString& idStr) {bool ok;int id = idStr.toInt(&ok);return ok && id > 0; // 假设业务ID需为正整数
}// 使用:
if (!isValidBusinessId(businessMatch.captured(1))) {qWarning() << "Invalid business ID:" << businessMatch.captured(1);continue; // 跳过无效数据
}
2. 改进正则表达式
// 严格匹配完整业务数据条目
QRegularExpression businessRegExp(R"(^(\d+):([^;]+);$)");// 使用带锚点的正则并逐行处理
QStringList lines = dataText.split('\n');
for (const QString& line : lines) {QRegularExpressionMatch match = businessRegExp.match(line.trimmed());if (match.hasMatch()) {// 处理匹配数据} else if (!line.isEmpty()) {qWarning() << "Invalid business data line:" << line;}
}
3. 数据冲突处理
// 检测重复业务ID
if (businessData.contains(businessId)) {qWarning() << "Duplicate business ID:" << businessId;// 可选:合并数据而非覆盖businessData[businessId] += timeValues;continue;
}
4. 性能优化
// 使用const迭代器避免临时列表
for (auto it = businessData.constBegin(); it != businessData.constEnd(); ++it) {int businessId = it.key();if (!weights.contains(businessId)) {weights[businessId] = 1;}
}
5. 用户反馈增强
// 收集详细错误信息
QStringList errorMessages;// 在解析过程中记录错误
errorMessages.append("第5行: 无效的业务ID格式");// 最终显示所有错误
if (!errorMessages.isEmpty()) {QMessageBox::warning(this, "数据解析错误", "发现以下问题:\n" + errorMessages.join('\n'));return false;
}
四、扩展功能建议
1. 添加数据校验
// 验证时间点顺序
bool isValidTimeSeries(const QList<QPair<int, int>>& timeValues) {if (timeValues.size() <= 1) return true;for (int i = 1; i < timeValues.size(); ++i) {if (timeValues[i].first <= timeValues[i-1].first) {return false; // 时间点必须递增}}return true;
}
2. 支持更多输入格式
// 支持JSON格式输入
bool parseBusinessDataFromJson(const QString& jsonText) {QJsonParseError error;QJsonDocument doc = QJsonDocument::fromJson(jsonText.toUtf8(), &error);if (error.error != QJsonParseError::NoError) {qWarning() << "JSON解析错误:" << error.errorString();return false;}// 解析JSON数据...return true;
}
3. 增加配置选项
// 配置结构体
struct ParseOptions {bool allowDuplicateIds = false;int defaultWeight = 1;bool strictMode = true;
};// 函数重载支持配置
bool parseBusinessData(const ParseOptions& options = ParseOptions());
五、测试用例建议
1. 正常情况测试
// 输入
"1:10-20,30-40;2:50-60;"
"1:5;2:3;"// 预期结果
businessData = {{1, [(10,20), (30,40)]},{2, [(50,60)]}
}
weights = {{1, 5},{2, 3}
}
2. 边界情况测试
- 空输入
- 只有业务数据,没有权重数据
- 只有权重数据,没有业务数据
3. 异常情况测试
- 无效业务ID(如"abc:10-20;")
- 重复业务ID
- 格式错误(如缺少分号)
4. 默认值测试
- 验证未明确设置权重的业务是否被赋予默认权重
- 验证默认权重值是否可配置
六、总结
该函数实现了基本的数据解析功能,但在错误处理、数据验证和用户反馈方面有改进空间。通过增强正则表达式、添加详细的错误日志、优化数据处理逻辑,可以提高代码的健壮性和可维护性。建议根据实际业务需求扩展功能,如支持更多输入格式、增加配置选项和完善测试用例。