Files
2026-11-06 01:04:35 +08:00

95 lines
3.9 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "conversion.h"
#include <QRegularExpression>
#include <cmath>
namespace Conversion {
QStringList units(Category category)
{
if (category == Category::Temperature)
return {QStringLiteral("摄氏度 °C"), QStringLiteral("华氏度 °F"),
QStringLiteral("开尔文 K")};
return {QStringLiteral("毫米 mm"), QStringLiteral("厘米 cm"),
QStringLiteral("米 m"), QStringLiteral("千米 km"),
QStringLiteral("英寸 in"), QStringLiteral("英尺 ft")};
}
Result convert(const QString &text, Category category, int from, int to)
{
Result result;
const QString input = text.trimmed();
// 先检查完整输入,避免把“12abc”误当成有效数值。
static const QRegularExpression number(
QStringLiteral("^[+-]?(?:[0-9]+(?:\\.[0-9]*)?|\\.[0-9]+)(?:[eE][+-]?[0-9]+)?$"));
if (!number.match(input).hasMatch()) {
result.error = QStringLiteral("请输入完整的数值,例如 25、-10.5 或 1e3;小数点使用英文句点。");
return result;
}
bool ok = false;
const double value = input.toDouble(&ok);
if (!ok || !std::isfinite(value)) {
result.error = QStringLiteral("输入超出了可计算的数值范围,请减小数值。");
return result;
}
const QStringList names = units(category);
if (from < 0 || to < 0 || from >= names.size() || to >= names.size()) {
result.error = QStringLiteral("请选择有效的单位。");
return result;
}
if (category == Category::Temperature) {
// 先统一为摄氏度,再换算为目标单位,避免为每对单位各写一套公式。
double celsius = value;
QString first;
if (from == 1) {
celsius = (value - 32.0) / 1.8;
first = QStringLiteral("先换成摄氏度:C = (F − 32) ÷ 1.8。");
} else if (from == 2) {
celsius = value - 273.15;
first = QStringLiteral("先换成摄氏度:C = K − 273.15。");
} else {
first = QStringLiteral("输入已经是摄氏度,可直接作为中间值。");
}
if (celsius < -273.15 - 1e-9) {
result.error = QStringLiteral("温度不能低于绝对零度:−273.15 °C / −459.67 °F / 0 K。");
return result;
}
// 允许边界处的浮点舍入误差,避免把绝对零度误判为非法输入。
if (celsius < -273.15)
celsius = -273.15;
QString second;
if (to == 1) {
result.value = celsius * 1.8 + 32.0;
second = QStringLiteral("再换成华氏度:F = C × 1.8 + 32。");
} else if (to == 2) {
result.value = celsius + 273.15;
second = QStringLiteral("再换成开尔文:K = C + 273.15。");
} else {
result.value = celsius;
second = QStringLiteral("目标是摄氏度,中间值就是结果。");
}
result.explanation = first + QStringLiteral("\n") + second;
} else {
if (value < 0.0) {
result.error = QStringLiteral("本工具换算的是长度,输入值不能为负数。");
return result;
}
const double metersPerUnit[] = {0.001, 0.01, 1.0, 1000.0, 0.0254, 0.3048};
result.value = value * (metersPerUnit[from] / metersPerUnit[to]);
result.explanation =
QStringLiteral("以米为统一单位:结果 = 输入值 × 源单位的米数 ÷ 目标单位的米数。\n"
"本次计算:%1 × %2 ÷ %3。")
.arg(input)
.arg(metersPerUnit[from], 0, 'g', 12)
.arg(metersPerUnit[to], 0, 'g', 12);
}
if (!std::isfinite(result.value)) {
result.error = QStringLiteral("换算结果超出了可显示的数值范围。");
return result;
}
if (result.value == 0.0)
result.value = 0.0; // 避免显示 -0。
result.ok = true;
return result;
}
}