| 179 | } |
| 180 | |
| 181 | QVariant mini_formula_evaluator_t::parse_function(const QString& base_sheet, const QString& func) |
| 182 | { |
| 183 | static const QRegularExpression re(R"(^([A-Za-z_][A-Za-z0-9_]*)\((.*)\)$)"); |
| 184 | const auto m = re.match(func.trimmed()); |
| 185 | if (!m.hasMatch()) return {}; |
| 186 | |
| 187 | const QString name = m.captured(1).toUpper(); |
| 188 | const QString args_str = m.captured(2).trimmed(); |
| 189 | const QStringList args = split_args_top_level(args_str); |
| 190 | |
| 191 | auto eval_arg_number = [&](const QString& a) -> double { |
| 192 | const QVariant v = eval(base_sheet, a); |
| 193 | return to_double_or_nan(v); |
| 194 | }; |
| 195 | |
| 196 | if (name == "SUM" || name == "AVERAGE" || name == "MIN" || name == "MAX") { |
| 197 | double acc = 0.0; |
| 198 | double mn = std::numeric_limits<double>::infinity(); |
| 199 | double mx = -std::numeric_limits<double>::infinity(); |
| 200 | int cnt = 0; |
| 201 | |
| 202 | auto consume_value = [&](double d) { |
| 203 | if (std::isnan(d)) return; |
| 204 | acc += d; |
| 205 | mn = std::min(mn, d); |
| 206 | mx = std::max(mx, d); |
| 207 | ++cnt; |
| 208 | }; |
| 209 | |
| 210 | for (const QString& a0 : args) { |
| 211 | const QString a = a0.trimmed(); |
| 212 | |
| 213 | // range: A1:B3 or Sheet1!A1:B3 |
| 214 | static const QRegularExpression re_sheet(R"(^([^!]+)!(.+)$)"); |
| 215 | static const QRegularExpression re_range(R"(^(\$?[A-Za-z]+\$?\d+):(\$?[A-Za-z]+\$?\d+)$)"); |
| 216 | |
| 217 | QString sheet = base_sheet; |
| 218 | QString range = a; |
| 219 | |
| 220 | const auto ms = re_sheet.match(a); |
| 221 | if (ms.hasMatch()) { |
| 222 | sheet = ms.captured(1).trimmed(); |
| 223 | range = ms.captured(2).trimmed(); |
| 224 | } |
| 225 | |
| 226 | const auto mr = re_range.match(range); |
| 227 | if (mr.hasMatch()) { |
| 228 | int r1=0,c1=0,r2=0,c2=0; |
| 229 | if (!try_parse_cell_ref(mr.captured(1), r1, c1)) continue; |
| 230 | if (!try_parse_cell_ref(mr.captured(2), r2, c2)) continue; |
| 231 | if (r1 > r2) std::swap(r1, r2); |
| 232 | if (c1 > c2) std::swap(c1, c2); |
| 233 | for (int r = r1; r <= r2; ++r) { |
| 234 | for (int c = c1; c <= c2; ++c) { |
| 235 | consume_value(to_double_or_nan(eval_cell(sheet, r, c))); |
| 236 | } |
| 237 | } |
| 238 | continue; |
nothing calls this directly
no test coverage detected