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 <QRegExp>
#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 QRegExp funcExpr ("(-)?([a-zA-Z]*[0-9]*)?\\‍((.+)\\‍)")
 
const QRegExp funcExprInteger ("(-)?\\‍((.+)\\‍)")
 
const QRegExp integerExpr ("(-)?([0-9]+)")
 
const QRegExp 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 QRegExp funcExpr ( "(-)?([a-zA-Z]*[0-9]*)?\\‍((.+)\\‍)" )

◆ funcExprInteger()

const QRegExp funcExprInteger ( "(-)?\\‍((.+)\\‍)" )

◆ integerExpr()

const QRegExp integerExpr ( "(-)?([0-9]+)" )

◆ numberExpr()

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

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 532 of file kis_num_parser.cpp.

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

References funcExprInteger(), integerExpr(), 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 437 of file kis_num_parser.cpp.

438{
439
440 noProblem = true;
441
442 QString exprDestructible = expr;
443
444 char nextOp = '+';
445 double result = 0.0;
446
447 while (!exprDestructible.isEmpty()) {
448
449 double sign = (nextOp == '-') ? -1 : 1;
450 QString part = extractSubExprLevel1(exprDestructible, nextOp, noProblem);
451
452 if( !noProblem) {
453 return 0.0;
454 }
455
456 if (sign > 0) {
457 result += treatLevel2Int(part, noProblem);
458 } else {
459 result -= treatLevel2Int(part, noProblem);
460 }
461
462 if(!noProblem){
463 return 0.0;
464 }
465 }
466
467 return result;
468
469}
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 479 of file kis_num_parser.cpp.

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