mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[FEATURE] search string update
- added regexp_replace operator - check types on comparison (QgsSearchTreeValue::compare now returns QgsSearchTreeValue for error reporting) - field calculator shows expression errors. - update node types and operators in sip bindings
This commit is contained in:
parent
7d74fe0453
commit
6c26773f9b
@ -12,7 +12,8 @@ class QgsSearchTreeNode
|
||||
tOperator = 1,
|
||||
tNumber,
|
||||
tColumnRef,
|
||||
tString
|
||||
tString,
|
||||
tNodeList,
|
||||
};
|
||||
|
||||
//! possible operators
|
||||
@ -27,6 +28,7 @@ class QgsSearchTreeNode
|
||||
opPLUS,
|
||||
opMINUS,
|
||||
opMUL,
|
||||
opMOD,
|
||||
opDIV,
|
||||
opPOW,
|
||||
opSQRT,
|
||||
@ -36,31 +38,50 @@ class QgsSearchTreeNode
|
||||
opASIN,
|
||||
opACOS,
|
||||
opATAN,
|
||||
opATAN2,
|
||||
|
||||
// conversion
|
||||
opTOINT,
|
||||
opTOREAL,
|
||||
opTOSTRING,
|
||||
|
||||
// coordinates
|
||||
opX,
|
||||
opY,
|
||||
opXAT,
|
||||
opYAT,
|
||||
|
||||
// measuring
|
||||
opLENGTH,
|
||||
opAREA,
|
||||
opPERIMETER,
|
||||
|
||||
// feature id
|
||||
opID,
|
||||
|
||||
// comparison
|
||||
opEQ, // =
|
||||
opNE, // != resp. <>
|
||||
opGT, // >
|
||||
opLT, // <
|
||||
opGE, // >=
|
||||
opLE, // <=
|
||||
opRegexp, // ~
|
||||
opLike, // LIKE
|
||||
opISNULL, // IS NULL
|
||||
opISNOTNULL, // IS NOT NULL
|
||||
opEQ, // =
|
||||
opNE, // != resp. <>
|
||||
opGT, // >
|
||||
opLT, // <
|
||||
opGE, // >=
|
||||
opLE, // <=
|
||||
opRegexp, // ~
|
||||
opLike, // LIKE
|
||||
opILike, // ILIKE
|
||||
opIN, // IN
|
||||
opNOTIN, // NOT IN
|
||||
|
||||
// string handling
|
||||
opCONCAT,
|
||||
opLOWER,
|
||||
opUPPER,
|
||||
opREPLACE,
|
||||
opREGEXPREPLACE,
|
||||
opSTRLEN,
|
||||
opSUBSTR,
|
||||
|
||||
opROWNUM
|
||||
};
|
||||
@ -177,8 +198,8 @@ class QgsSearchTreeValue
|
||||
QgsSearchTreeValue( double number );
|
||||
QgsSearchTreeValue( int error, QString errorMsg );
|
||||
|
||||
static int compare( QgsSearchTreeValue& value1, QgsSearchTreeValue& value2,
|
||||
Qt::CaseSensitivity = Qt::CaseSensitive );
|
||||
static QgsSearchTreeValue compare( QgsSearchTreeValue& value1, QgsSearchTreeValue& value2,
|
||||
Qt::CaseSensitivity = Qt::CaseSensitive );
|
||||
|
||||
bool isNumeric();
|
||||
bool isError();
|
||||
|
@ -54,7 +54,8 @@ Der Feldrechner erlaubt Ihnen Felder mit Ausdrücken zu setzen.
|
||||
<tr><td>upper(<tt>a</tt>)</td><td>Zeichenkette <tt>a</tt> in Großbuchstaben umwandeln</td></tr>
|
||||
<tr><td>length(<tt>a</tt>)</td><td>Länge der Zeichenkette <tt>a</tt></td></tr>
|
||||
<tr><td>atan2(y,x)</td><td>Arcustangens von y/x mit Vorzeichen der beiden Argumenten, um den Quadranten des Ergebnisses zu bestimmen.</td></tr>
|
||||
<tr><td>replace(<tt>a</tt>,<i>ersetzedieses</i>,<i>durchjenes</i>)</td><td>In der Zeichenkette <tt>a</tt> <i>ersetzedieses</i> durch <i>durchjenes</i> ersetzen.</td></td>
|
||||
<tr><td>replace(<tt>a</tt>,<i>streiche</i>,<i>setze</i>)</td><td>In der Zeichenkette <tt>a</tt> <i>streiche</i> durch <i>setze</i> ersetzen.</td></td>
|
||||
<tr><td>regexp_replace(<tt>a</tt>,<i>streiche</i>,<i>setze</i>)</td><td>In der Zeichenkette <tt>a</tt> den regulären Ausdruck <i>streiche</i> durch <i>setze</i> ersetzen.</td></td>
|
||||
<tr><td>substr(<tt>a</tt>,<i>von</i>,<i>länge</i>)</td><td><i>lünge</i> Zeichen der Zeichenkette <tt>a</tt> ab Stelle <i>von</i> (Das erste Zeichen hat den Index 1)</td></td>
|
||||
<tr><td><tt>a</tt> || <tt>b</tt></td><td>Zeichenkette <tt>a</tt> and <tt>b</tt> zusammenziehen</td></tr>
|
||||
<tr><td>$rownum</td><td>Aktuelle Zeilennummer</td></tr>
|
||||
|
@ -33,6 +33,7 @@ The field calculator allows you to update fields with expressions.
|
||||
<tr><td>length(<tt>a</tt>)</td><td>length of string <tt>a</tt></td></tr>
|
||||
<tr><td>atan2(y,x)</td><td>arcustangens of y/x using the signs of the two arguments to determine the quadrant of the result.</td></tr>
|
||||
<tr><td>replace(<tt>a</tt>,<i>replacethis</i>,<i>withthat</i>)</td><td>replace <i>replacethis</i> with <i>withthat</i> in string <tt>a</tt></td></td>
|
||||
<tr><td>regexp_replace(<tt>a</tt>,<i>replacethis</i>,<i>withthat</i>)</td><td>replace the regular expression <i>replacethis</i> with <i>withthat</i> in string <tt>a</tt></td></td>
|
||||
<tr><td>substr(<tt>a</tt>,from,len)</td><td>len characters of string <tt>a</tt> starting from from (first character index is 1)</td></td>
|
||||
<tr><td><tt>a</tt> || <tt>b</tt></td><td>concatenate strings <tt>a</tt> and <tt>b</tt></td></tr>
|
||||
<tr><td>$rownum</td><td>number current row</td></tr>
|
||||
|
@ -148,6 +148,7 @@ void QgsFieldCalculator::accept()
|
||||
//go through all the features and change the new attribute
|
||||
QgsFeature feature;
|
||||
bool calculationSuccess = true;
|
||||
QString error;
|
||||
|
||||
bool onlySelected = ( mOnlyUpdateSelectedCheckBox->checkState() == Qt::Checked );
|
||||
QgsFeatureIds selectedIds = mVectorLayer->selectedFeaturesIds();
|
||||
@ -183,6 +184,7 @@ void QgsFieldCalculator::accept()
|
||||
else
|
||||
{
|
||||
calculationSuccess = false;
|
||||
error = searchTree->errorMsg();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -225,7 +227,7 @@ void QgsFieldCalculator::accept()
|
||||
|
||||
if ( !calculationSuccess )
|
||||
{
|
||||
QMessageBox::critical( 0, tr( "Error" ), tr( "An error occured while evaluating the calculation string." ) );
|
||||
QMessageBox::critical( 0, tr( "Error" ), tr( "An error occured while evaluating the calculation string:\n%1" ).arg( error ) );
|
||||
mVectorLayer->destroyEditCommand();
|
||||
return;
|
||||
}
|
||||
|
@ -106,6 +106,7 @@ string "'"{str_char}*"'"
|
||||
"atan2" { yylval.op = QgsSearchTreeNode::opATAN2; return FUNCTION2;}
|
||||
|
||||
"replace" { yylval.op = QgsSearchTreeNode::opREPLACE; return FUNCTION3;}
|
||||
"regexp_replace" { yylval.op = QgsSearchTreeNode::opREGEXPREPLACE; return FUNCTION3;}
|
||||
"substr" { yylval.op = QgsSearchTreeNode::opSUBSTR; return FUNCTION3;}
|
||||
|
||||
"||" { return CONCAT; }
|
||||
|
@ -205,8 +205,8 @@ QString QgsSearchTreeNode::makeSearchString()
|
||||
mOp == opASIN || mOp == opACOS || mOp == opATAN ||
|
||||
mOp == opTOINT || mOp == opTOREAL || mOp == opTOSTRING ||
|
||||
mOp == opLOWER || mOp == opUPPER || mOp == opSTRLEN ||
|
||||
mOp == opATAN2 || mOp == opREPLACE || mOp == opSUBSTR ||
|
||||
mOp == opXAT || mOp == opYAT )
|
||||
mOp == opATAN2 || mOp == opREPLACE || mOp == opREGEXPREPLACE ||
|
||||
mOp == opSUBSTR || mOp == opXAT || mOp == opYAT )
|
||||
{
|
||||
// functions
|
||||
switch ( mOp )
|
||||
@ -226,6 +226,7 @@ QString QgsSearchTreeNode::makeSearchString()
|
||||
case opATAN2: str += "atan2"; break;
|
||||
case opSTRLEN: str += "length"; break;
|
||||
case opREPLACE: str += "replace"; break;
|
||||
case opREGEXPREPLACE: str += "regexp_replace"; break;
|
||||
case opSUBSTR: str += "substr"; break;
|
||||
case opXAT: str += "xat"; break;
|
||||
case opYAT: str += "yat"; break;
|
||||
@ -407,7 +408,6 @@ bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, QgsFeature &f )
|
||||
}
|
||||
|
||||
QgsSearchTreeValue value1, value2;
|
||||
int res;
|
||||
|
||||
switch ( mOp )
|
||||
{
|
||||
@ -437,6 +437,7 @@ bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, QgsFeature &f )
|
||||
case opLT:
|
||||
case opGE:
|
||||
case opLE:
|
||||
{
|
||||
if ( !getValue( value1, mLeft, fields, f ) || !getValue( value2, mRight, fields, f ) )
|
||||
return false;
|
||||
|
||||
@ -446,20 +447,27 @@ bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, QgsFeature &f )
|
||||
return false;
|
||||
}
|
||||
|
||||
res = QgsSearchTreeValue::compare( value1, value2 );
|
||||
QgsSearchTreeValue res = QgsSearchTreeValue::compare( value1, value2 );
|
||||
if ( res.isError() )
|
||||
{
|
||||
mError = QString( "%1 [%2]" ).arg( res.string() ).arg( res.number() );
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ( mOp )
|
||||
{
|
||||
case opEQ: return res == 0;
|
||||
case opNE: return res != 0;
|
||||
case opGT: return res > 0;
|
||||
case opLT: return res < 0;
|
||||
case opGE: return res >= 0;
|
||||
case opLE: return res <= 0;
|
||||
case opEQ: return res.number() == 0.0;
|
||||
case opNE: return res.number() != 0.0;
|
||||
case opGT: return res.number() > 0.0;
|
||||
case opLT: return res.number() < 0.0;
|
||||
case opGE: return res.number() >= 0.0;
|
||||
case opLE: return res.number() <= 0.0;
|
||||
default:
|
||||
mError = QObject::tr( "Unexpected state when evaluating operator!" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case opIN:
|
||||
case opNOTIN:
|
||||
@ -478,9 +486,9 @@ bool QgsSearchTreeNode::checkAgainst( const QgsFieldMap& fields, QgsFeature &f )
|
||||
return false;
|
||||
}
|
||||
|
||||
res = QgsSearchTreeValue::compare( value1, value2 );
|
||||
QgsSearchTreeValue res = QgsSearchTreeValue::compare( value1, value2 );
|
||||
|
||||
if ( res == 0 )
|
||||
if ( res.isNumeric() && res.number() == 0.0 )
|
||||
{
|
||||
// found
|
||||
return mOp == opIN;
|
||||
@ -561,16 +569,17 @@ bool QgsSearchTreeNode::getValue( QgsSearchTreeValue& value,
|
||||
case 2:
|
||||
mError = QObject::tr( "Division by zero." );
|
||||
break;
|
||||
|
||||
// these should never happen (no need to translate)
|
||||
case 3:
|
||||
mError = QObject::tr( "Unknown operator: %1" ).arg( value.string() );
|
||||
break;
|
||||
case 4:
|
||||
mError = QObject::tr( "Unknown token: %1" ).arg( value.string() );
|
||||
break;
|
||||
case 5:
|
||||
mError = QObject::tr( "Expression error: %1" ).arg( value.string() );
|
||||
break;
|
||||
default:
|
||||
mError = QObject::tr( "Unknown error!" );
|
||||
mError = QObject::tr( "Unknown error %1: %2" ).arg( value.number() ).arg( value.string() );
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
@ -779,6 +788,16 @@ QgsSearchTreeValue QgsSearchTreeNode::valueAgainst( const QgsFieldMap& fields, Q
|
||||
return QgsSearchTreeValue( value1.string().length() );
|
||||
case opREPLACE:
|
||||
return QgsSearchTreeValue( value1.string().replace( value2.string(), value3.string() ) );
|
||||
case opREGEXPREPLACE:
|
||||
{
|
||||
QRegExp re( value2.string() );
|
||||
if ( !re.isValid() )
|
||||
{
|
||||
return QgsSearchTreeValue( 5, QObject::tr( "Invalid regular expression '%1': %2" ).arg( value2.string() ).arg( re.errorString() ) );
|
||||
}
|
||||
|
||||
return QgsSearchTreeValue( value1.string().replace( re, value3.string() ) );
|
||||
}
|
||||
case opSUBSTR:
|
||||
return QgsSearchTreeValue( value1.string().mid( value2.number() - 1, value3.number() ) );
|
||||
default:
|
||||
@ -884,7 +903,7 @@ void QgsSearchTreeNode::append( QList<QgsSearchTreeNode *> nodes )
|
||||
}
|
||||
}
|
||||
|
||||
int QgsSearchTreeValue::compare( QgsSearchTreeValue& value1, QgsSearchTreeValue& value2, Qt::CaseSensitivity cs )
|
||||
QgsSearchTreeValue QgsSearchTreeValue::compare( QgsSearchTreeValue& value1, QgsSearchTreeValue& value2, Qt::CaseSensitivity cs )
|
||||
{
|
||||
if ( value1.isNumeric() || value2.isNumeric() )
|
||||
{
|
||||
@ -892,27 +911,44 @@ int QgsSearchTreeValue::compare( QgsSearchTreeValue& value1, QgsSearchTreeValue&
|
||||
|
||||
// convert to numbers if needed
|
||||
double val1, val2;
|
||||
bool ok;
|
||||
if ( value1.isNumeric() )
|
||||
{
|
||||
val1 = value1.number();
|
||||
}
|
||||
else
|
||||
val1 = value1.string().toDouble();
|
||||
{
|
||||
val1 = value1.string().toDouble( &ok );
|
||||
if ( !ok )
|
||||
{
|
||||
return QgsSearchTreeValue( 5, QObject::tr( "Value '%1' is not numeric" ).arg( value1.string() ) );
|
||||
}
|
||||
}
|
||||
if ( value2.isNumeric() )
|
||||
{
|
||||
val2 = value2.number();
|
||||
}
|
||||
else
|
||||
val2 = value2.string().toDouble();
|
||||
{
|
||||
val2 = value2.string().toDouble( &ok );
|
||||
if ( !ok )
|
||||
{
|
||||
return QgsSearchTreeValue( 5, QObject::tr( "Value '%1' is not numeric" ).arg( value2.string() ) );
|
||||
}
|
||||
}
|
||||
|
||||
QgsDebugMsgLevel( "NUM_COMP: " + QString::number( val1 ) + " ~ " + QString::number( val2 ), 2 );
|
||||
|
||||
if ( val1 < val2 )
|
||||
return -1;
|
||||
return QgsSearchTreeValue( -1.0 );
|
||||
else if ( val1 > val2 )
|
||||
return 1;
|
||||
return QgsSearchTreeValue( 1.0 );
|
||||
else
|
||||
return 0;
|
||||
return QgsSearchTreeValue( 0.0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// string comparison
|
||||
return value1.string().compare( value2.string(), cs );
|
||||
return QgsSearchTreeValue(( double ) value1.string().compare( value2.string(), cs ) );
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ class CORE_EXPORT QgsSearchTreeNode
|
||||
};
|
||||
|
||||
//! possible operators
|
||||
//! TODO: sync the python bindings
|
||||
enum Operator
|
||||
{
|
||||
// binary
|
||||
@ -116,6 +117,7 @@ class CORE_EXPORT QgsSearchTreeNode
|
||||
opLOWER,
|
||||
opUPPER,
|
||||
opREPLACE,
|
||||
opREGEXPREPLACE,
|
||||
opSTRLEN,
|
||||
opSUBSTR,
|
||||
|
||||
@ -269,8 +271,8 @@ class CORE_EXPORT QgsSearchTreeValue
|
||||
QgsSearchTreeValue( double number ) { mType = valNumber; mNumber = number; }
|
||||
QgsSearchTreeValue( int error, QString errorMsg ) { mType = valError; mNumber = error; mString = errorMsg; }
|
||||
|
||||
static int compare( QgsSearchTreeValue& value1, QgsSearchTreeValue& value2,
|
||||
Qt::CaseSensitivity = Qt::CaseSensitive );
|
||||
static QgsSearchTreeValue compare( QgsSearchTreeValue& value1, QgsSearchTreeValue& value2,
|
||||
Qt::CaseSensitivity = Qt::CaseSensitive );
|
||||
|
||||
bool isNumeric() { return mType == valNumber; }
|
||||
bool isError() { return mType == valError; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user