Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_num_parser.cpp File Reference
#include "kis_num_parser.h"
#include <qnumeric.h>
#include <qmath.h>
#include <QVector>
#include <QRegularExpression>
#include <QStringList>
#include <QVariant>
#include <QLocale>
#include <iostream>

Go to the source code of this file.

Namespaces

namespace  KisNumericParser
 the namespace contains functions to transform math expression written as QString in numbers.
 

Functions

QString extractSubExprLevel1 (QString &expr, char &nextOp, bool &noProblem)
 extractSubExprLevel1 extract from an expression the part of an expression that need to be treated recursively before computing level 1 operations (+, -).
 
QString extractSubExprLevel2 (QString &expr, char &nextOp, bool &noProblem)
 extractSubExprLevel2 extract from an expression the part of an expression that need to be treated recursively before computing level 2 operations (*, /).
 
const QRegularExpression funcExpr ("^(-)?([a-zA-Z]*[0-9]*)?\\‍((.+)\\‍)$")
 
const QRegularExpression funcExprInteger ("^(-)?\\‍((.+)\\‍)$")
 
const QRegularExpression integerExpr ("^(-)?([0-9]+)$")
 
const QRegularExpression numberExpr ("^(-)?([0-9]+\\.?[0-9]*(e[0-9]*)?)$")
 
int KisNumericParser::parseIntegerMathExpr (QString const &expr, bool *noProblem=0)
 parse an expression to an int.
 
double KisNumericParser::parseSimpleMathExpr (QString const &expr, bool *noProblem=0)
 parse an expression to a double.
 
double treatFuncs (QString const &expr, bool &noProblem)
 treatFuncs treat the last level of recursion: parenthesis and functions.
 
double treatFuncsInt (QString const &expr, bool &noProblem)
 treatFuncs treat the last level of recursion: parenthesis
 
double treatLevel1 (const QString &expr, bool &noProblem)
 treatLevel1 treat an expression at the first level of recursion.
 
double treatLevel1Int (QString const &expr, bool &noProblem)
 treatLevel1 treat an expression at the first level of recursion.
 
double treatLevel2 (QString const &expr, bool &noProblem)
 treatLevel2 treat a subexpression at the second level of recursion.
 
double treatLevel2Int (const QString &expr, bool &noProblem)
 treatLevel2 treat a subexpression at the second level of recursion.
 
double treatLevel3 (const QString &expr, bool &noProblem)
 treatLevel3 treat a subexpression at the third level of recursion.
 

Variables

const QVector< char > opLevel1 = {'+', '-'}
 
const QVector< char > opLevel2 = {'*', '/'}
 
const QStringList supportedFuncs = {"", "cos", "sin", "tan", "acos", "asin", "atan", "exp", "ln", "log10", "abs"}
 

Function Documentation

◆ extractSubExprLevel1()

QString extractSubExprLevel1 ( QString & expr,
char & nextOp,
bool & noProblem )
inline

extractSubExprLevel1 extract from an expression the part of an expression that need to be treated recursively before computing level 1 operations (+, -).

Parameters
exprThe expression to treat, the part returned will be removed.
nextOpThis reference, in case of success, will hold the first level operation identified as separator ('+' or '-')
noProblemA reference to a bool, set to true if there was no problem, false otherwise.
Returns
The first part of the expression that doesn't contain first level operations not nested within parenthesis.

Definition at line 94 of file kis_num_parser.cpp.

94 {
95
96 QString ret;
97
98 int subCount = 0;
99
100 bool lastMetIsNumber = false;
101
102 for(int i = 0; i < expr.size(); i++){
103
104 if (expr.at(i) == '(') {
105 subCount++;
106 }
107
108 if (expr.at(i) == ')') {
109 subCount--;
110 }
111
112 if (subCount < 0) {
113 noProblem = false;
114 return ret;
115 }
116
117 if(i == expr.size()-1 && subCount == 0){
118 ret = expr;
119 expr.clear();
120 break;
121 }
122
123 if( (expr.at(i) == '+' || expr.at(i) == '-') &&
124 subCount == 0) {
125
126 if (expr.at(i) == '-' &&
127 i < expr.size()-1) {
128
129 bool cond = !expr.at(i+1).isSpace();
130
131 if (cond && !lastMetIsNumber) {
132 continue;
133 }
134
135 }
136
137 ret = expr.mid(0, i).trimmed();
138 nextOp = expr.at(i).toLatin1();
139 expr = expr.mid(i+1);
140 break;
141
142 }
143
144 if (expr.at(i).isDigit()) {
145 lastMetIsNumber = true;
146 } else if (expr.at(i) != '.' &&
147 !expr.at(i).isSpace()) {
148 lastMetIsNumber = false;
149 }
150
151 }
152
153 noProblem = true;
154 return ret;
155}

◆ extractSubExprLevel2()

QString extractSubExprLevel2 ( QString & expr,
char & nextOp,
bool & noProblem )
inline

extractSubExprLevel2 extract from an expression the part of an expression that need to be treated recursively before computing level 2 operations (*, /).

Parameters
exprThe expression to treat, the part returned will be removed.
nextOpThis reference, in case of success, will hold the first level operation identified as separator ('*' or '/')
noProblemA reference to a bool, set to true if there was no problem, false otherwise.
Returns
The first part of the expression that doesn't contain second level operations not nested within parenthesis.

Definition at line 165 of file kis_num_parser.cpp.

165 {
166
167 QString ret;
168
169 int subCount = 0;
170
171 for(int i = 0; i < expr.size(); i++){
172
173 if (expr.at(i) == '(') {
174 subCount++;
175 }
176
177 if (expr.at(i) == ')') {
178 subCount--;
179 }
180
181 if (subCount < 0) {
182 noProblem = false;
183 return ret;
184 }
185
186 if(i == expr.size()-1 && subCount == 0){
187 ret = expr;
188 expr.clear();
189 break;
190 }
191
192 if( (expr.at(i) == '*' || expr.at(i) == '/') &&
193 subCount == 0) {
194
195 ret = expr.mid(0, i).trimmed();
196 nextOp = expr.at(i).toLatin1();
197 expr = expr.mid(i+1);
198 break;
199
200 }
201
202 }
203
204 noProblem = true;
205 return ret;
206}

◆ funcExpr()

const QRegularExpression funcExpr ( "^(-)?([a-zA-Z]*[0-9]*)?\\‍((.+)\\‍)$" )

◆ funcExprInteger()

const QRegularExpression funcExprInteger ( "^(-)?\\‍((.+)\\‍)$" )

◆ integerExpr()

const QRegularExpression integerExpr ( "^(-)?([0-9]+)$" )

◆ numberExpr()

const QRegularExpression numberExpr ( "^(-)?([0-9]+\\.?[0-9]*(e[0-9]*)?)$" )

◆ treatFuncs()

double treatFuncs ( QString const & expr,
bool & noProblem )

treatFuncs treat the last level of recursion: parenthesis and functions.

Parameters
exprThe expression to parse.
noProblemA reference to a bool set to true if no problem happened, false otherwise.
Returns
The value of the parsed subexpression or 0 in case of error.

The expression should not contain operators not nested anymore. The subexpressions within parenthesis will be treated by recalling the level 1 function.

Definition at line 362 of file kis_num_parser.cpp.

363{
364
365 noProblem = true;
366
367 QRegularExpression funcExp = funcExpr; //copy the expression in the current execution stack, to avoid errors for example when multiple thread call this function.
368 QRegularExpression numExp = numberExpr;
369 QRegularExpressionMatch match;
370
371 if (expr.trimmed().contains(funcExp, &match)) {
372
373 int sign = match.captured(1).isEmpty() ? 1 : -1;
374 QString func = match.captured(2).toLower();
375 QString subExpr = match.captured(3);
376
377 double val = treatLevel1(subExpr, noProblem);
378
379 if (!noProblem) {
380 return 0.0;
381 }
382
383 if (func.isEmpty()) {
384 return sign*val;
385 }
386
387 if (!supportedFuncs.contains(func)) {
388 noProblem = false;
389 return 0.0;
390 }
391
392 //trigonometry is done in degree
393 if (func == "cos") {
394 val = qCos(val/180*qAcos(-1));
395 } else if (func == "sin") {
396 val = qSin(val/180*qAcos(-1));
397 } else if (func == "tan") {
398 val = qTan(val/180*qAcos(-1));
399 } else if(func == "acos") {
400 val = qAcos(val)*180/qAcos(-1);
401 } else if (func == "asin") {
402 val = qAsin(val)*180/qAcos(-1);
403 } else if (func == "atan") {
404 val = qAtan(val)*180/qAcos(-1);
405 } else if (func == "exp") {
406 val = qExp(val);
407 } else if (func == "ln") {
408 val = qLn(val);
409 } else if (func == "log10") {
410 val = qLn(val)/qLn(10.0);
411 } else if (func == "abs") {
412 val = qAbs(val);
413 }
414
415 return sign*val;
416 } else if(expr.trimmed().contains(numExp)) {
417 return expr.toDouble(&noProblem);
418 }
419
420 double val = QLocale().toDouble(expr, &noProblem);
421
422 if(noProblem) {
423 return val;
424 }
425
426 noProblem = false;
427 return 0.0;
428
429}
const QStringList supportedFuncs
double treatLevel1(QString const &expr, bool &noProblem)
treatLevel1 treat an expression at the first level of recursion.
const QRegularExpression numberExpr("^(-)?([0-9]+\\.?[0-9]*(e[0-9]*)?)$")
const QRegularExpression funcExpr("^(-)?([a-zA-Z]*[0-9]*)?\\‍((.+)\\‍)$")

References funcExpr(), numberExpr(), sign(), supportedFuncs, and treatLevel1().

◆ treatFuncsInt()

double treatFuncsInt ( QString const & expr,
bool & noProblem )

treatFuncs treat the last level of recursion: parenthesis

Parameters
exprThe expression to parse.
noProblemA reference to a bool set to true if no problem happened, false otherwise.
Returns
The value of the parsed subexpression or 0 in case of error.

The expression should not contain operators not nested anymore. The subexpressions within parenthesis will be treated by recalling the level 1 function.

Definition at line 533 of file kis_num_parser.cpp.

534{
535
536 noProblem = true;
537
538 QRegularExpression funcExpInteger = funcExprInteger;
539 QRegularExpression numberExp = numberExpr;
540 QRegularExpressionMatch match;
541
542 if (expr.trimmed().contains(funcExpInteger, &match)) {
543
544 int sign = match.captured(1).isEmpty() ? 1 : -1;
545 QString subExpr = match.captured(2);
546
547 double val = treatLevel1Int(subExpr, noProblem);
548
549 if (!noProblem) {
550 return 0;
551 }
552
553 return sign*val;
554
555 } else if(expr.trimmed().contains(numberExp)) {
556 double value = QVariant(expr).toDouble(&noProblem);
557 return value;
558 }
559
560 noProblem = false;
561 return 0;
562
563}
float value(const T *src, size_t ch)
const QRegularExpression funcExprInteger("^(-)?\\‍((.+)\\‍)$")
double treatLevel1Int(QString const &expr, bool &noProblem)
treatLevel1 treat an expression at the first level of recursion.

References funcExprInteger(), numberExpr(), sign(), treatLevel1Int(), and value().

◆ treatLevel1()

double treatLevel1 ( const QString & expr,
bool & noProblem )

treatLevel1 treat an expression at the first level of recursion.

Parameters
exprThe expression to treat.
noProblemA reference to a bool set to true if no problem happened, false otherwise.
Returns
The value of the parsed expression or subexpression or 0 in case of error.

Definition at line 214 of file kis_num_parser.cpp.

215{
216
217 noProblem = true;
218
219 QString exprDestructible = expr;
220
221 char nextOp = '+';
222 double result = 0.0;
223
224 while (!exprDestructible.isEmpty()) {
225
226 double sign = (nextOp == '-') ? -1 : 1;
227 QString part = extractSubExprLevel1(exprDestructible, nextOp, noProblem);
228
229 if (!noProblem) {
230 return 0.0;
231 }
232
233 if (sign > 0) {
234 result += treatLevel2(part, noProblem);
235 } else {
236 result -= treatLevel2(part, noProblem);
237 }
238
239 if(!noProblem){
240 return 0.0;
241 }
242 }
243
244 return result;
245
246}
quint64 part(quint64 n1, quint64 n2, int p)
QString extractSubExprLevel1(QString &expr, char &nextOp, bool &noProblem)
extractSubExprLevel1 extract from an expression the part of an expression that need to be treated rec...
double treatLevel2(QString const &expr, bool &noProblem)
treatLevel2 treat a subexpression at the second level of recursion.

References extractSubExprLevel1(), part(), sign(), and treatLevel2().

◆ treatLevel1Int()

double treatLevel1Int ( QString const & expr,
bool & noProblem )

treatLevel1 treat an expression at the first level of recursion.

Parameters
exprThe expression to treat.
noProblemA reference to a bool set to true if no problem happened, false otherwise.
Returns
The value of the parsed expression or subexpression or 0 in case of error.

Definition at line 438 of file kis_num_parser.cpp.

439{
440
441 noProblem = true;
442
443 QString exprDestructible = expr;
444
445 char nextOp = '+';
446 double result = 0.0;
447
448 while (!exprDestructible.isEmpty()) {
449
450 double sign = (nextOp == '-') ? -1 : 1;
451 QString part = extractSubExprLevel1(exprDestructible, nextOp, noProblem);
452
453 if( !noProblem) {
454 return 0.0;
455 }
456
457 if (sign > 0) {
458 result += treatLevel2Int(part, noProblem);
459 } else {
460 result -= treatLevel2Int(part, noProblem);
461 }
462
463 if(!noProblem){
464 return 0.0;
465 }
466 }
467
468 return result;
469
470}
double treatLevel2Int(QString const &expr, bool &noProblem)
treatLevel2 treat a subexpression at the second level of recursion.

References extractSubExprLevel1(), part(), sign(), and treatLevel2Int().

◆ treatLevel2()

double treatLevel2 ( QString const & expr,
bool & noProblem )

treatLevel2 treat a subexpression at the second level of recursion.

Parameters
exprThe subexpression to treat.
noProblemA reference to a bool set to true if no problem happened, false otherwise.
Returns
The value of the parsed subexpression or 0 in case of error.

The expression should not contain first level operations not nested in parenthesis.

Definition at line 256 of file kis_num_parser.cpp.

257{
258
259 noProblem = true;
260
261 QString exprDestructible = expr;
262
263 char nextOp = '*';
264
265 QString part = extractSubExprLevel2(exprDestructible, nextOp, noProblem);
266
267 double result = treatLevel3(part, noProblem);
268
269 while (!exprDestructible.isEmpty()) {
270
271 if (!noProblem) {
272 return 0.0;
273 }
274
275 bool needToMultiply = (nextOp == '*');
276 part = extractSubExprLevel2(exprDestructible, nextOp, noProblem);
277
278 if (!noProblem) {
279 return 0.0;
280 }
281
282 if (needToMultiply) {
283 result *= treatLevel3(part, noProblem);
284 } else {
285 result /= treatLevel3(part, noProblem);
286 }
287 }
288
289 return result;
290}
QString extractSubExprLevel2(QString &expr, char &nextOp, bool &noProblem)
extractSubExprLevel2 extract from an expression the part of an expression that need to be treated rec...
double treatLevel3(QString const &expr, bool &noProblem)
treatLevel3 treat a subexpression at the third level of recursion.

References extractSubExprLevel2(), part(), and treatLevel3().

◆ treatLevel2Int()

double treatLevel2Int ( const QString & expr,
bool & noProblem )

treatLevel2 treat a subexpression at the second level of recursion.

Parameters
exprThe subexpression to treat.
noProblemA reference to a bool set to true if no problem happened, false otherwise.
Returns
The value of the parsed subexpression or 0 in case of error.

The expression should not contain first level operations not nested in parenthesis.

Definition at line 480 of file kis_num_parser.cpp.

481{
482
483 noProblem = true;
484
485 QString exprDestructible = expr;
486
487 char nextOp = '*';
488
489 QString part = extractSubExprLevel2(exprDestructible, nextOp, noProblem);
490
491 double result = treatFuncsInt(part, noProblem);
492
493 while (!exprDestructible.isEmpty()) {
494
495 if (!noProblem) {
496 return 0.0;
497 }
498
499 bool needToMultiply = (nextOp == '*');
500 part = extractSubExprLevel2(exprDestructible, nextOp, noProblem);
501
502 if (!noProblem) {
503 return 0.0;
504 }
505
506 if (needToMultiply) {
507 result *= treatFuncsInt(part, noProblem);
508 } else {
509
510 double val = treatFuncsInt(part, noProblem);
511
512 if(std::isinf(result/val) || qIsNaN(result/val)){
513 noProblem = false;
514 return 0.0;
515 }
516
517 result /= val;
518 }
519 }
520
521 return result;
522
523}
double treatFuncsInt(QString const &expr, bool &noProblem)
treatFuncs treat the last level of recursion: parenthesis

References extractSubExprLevel2(), part(), and treatFuncsInt().

◆ treatLevel3()

double treatLevel3 ( const QString & expr,
bool & noProblem )

treatLevel3 treat a subexpression at the third level of recursion.

Parameters
exprThe subexpression to treat.
noProblemA reference to a bool set to true if no problem happened, false otherwise.
Returns
The value of the parsed subexpression or 0 in case of error.

The expression should not contain first or second level operations not nested in parenthesis.

Definition at line 300 of file kis_num_parser.cpp.

301{
302
303 noProblem = true;
304
305 int indexPower = -1;
306 int indexCount = 0;
307 int subLevels = 0;
308
309 for (int i = 0; i < expr.size(); i++) {
310 if (expr.at(i) == '(') {
311 subLevels++;
312 } else if(expr.at(i) == ')') {
313 subLevels--;
314 if (subLevels < 0) {
315 noProblem = false;
316 return 0.0;
317 }
318 } else if (expr.at(i) == '^') {
319 if (subLevels == 0) {
320 indexPower = i;
321 indexCount++;
322 }
323 }
324 }
325
326 if (indexCount > 1 || indexPower + 1 >= expr.size()) {
327 noProblem = false;
328 return 0.0;
329 }
330
331 if (indexPower > -1) {
332
333 QStringList subExprs;
334 subExprs << expr.mid(0,indexPower);
335 subExprs << expr.mid(indexPower+1);
336
337 bool noProb1 = true;
338 bool noProb2 = true;
339
340 double base = treatFuncs(subExprs[0], noProb1);
341 double power = treatFuncs(subExprs[1], noProb2);
342
343 return qPow(base, power);
344
345 } else {
346 return treatFuncs(expr, noProblem);
347 }
348
349 noProblem = false;
350 return 0.0;
351
352}
double treatFuncs(QString const &expr, bool &noProblem)
treatFuncs treat the last level of recursion: parenthesis and functions.

References treatFuncs().

Variable Documentation

◆ opLevel1

const QVector<char> opLevel1 = {'+', '-'}

Definition at line 21 of file kis_num_parser.cpp.

21{'+', '-'};

◆ opLevel2

const QVector<char> opLevel2 = {'*', '/'}

Definition at line 22 of file kis_num_parser.cpp.

22{'*', '/'};

◆ supportedFuncs

const QStringList supportedFuncs = {"", "cos", "sin", "tan", "acos", "asin", "atan", "exp", "ln", "log10", "abs"}

Definition at line 24 of file kis_num_parser.cpp.

24{"", "cos", "sin", "tan", "acos", "asin", "atan", "exp", "ln", "log10", "abs"};