Skip to content

Commit 3fb2d9e

Browse files
committedOct 27, 2016
[expression] further improve replace() to support a map argument
1 parent 8b74201 commit 3fb2d9e

File tree

3 files changed

+65
-36
lines changed

3 files changed

+65
-36
lines changed
 

‎resources/function_help/json/replace

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
{
22
"name": "replace",
33
"type": "function",
4-
"description": "Returns a string with the supplied string or array of strings replaced by a string or an array of strings.",
5-
"arguments": [ {"arg":"string","description":"the input string"},
6-
{"arg":"before","description":"the string or array of strings to replace"},
7-
{"arg":"after","description":"the string or array of strings to use as a replacement"}],
8-
"examples": [ { "expression":"replace('QGIS SHOULD ROCK','SHOULD','DOES')", "returns":"'QGIS DOES ROCK'"},
9-
{ "expression":"replace('QGIS ABC',array('A','B','C'),array('X','Y','Z'))", "returns":"'QGIS XYZ'"},
10-
{ "expression":"replace('QGIS',array('Q','S'),'')", "returns":"'GI'"}
11-
]
4+
"description": "Returns a string with the supplied string, array, or map of strings replaced.",
5+
"variants": [
6+
{ "variant": "String & array variant",
7+
"variant_description": "Returns a string with the supplied string or array of strings replaced by a string or an array of strings.",
8+
"arguments": [ {"arg":"string","description":"the input string"},
9+
{"arg":"before","description":"the string or array of strings to replace"},
10+
{"arg":"after","description":"the string or array of strings to use as a replacement"}],
11+
"examples": [ { "expression":"replace('QGIS SHOULD ROCK','SHOULD','DOES')", "returns":"'QGIS DOES ROCK'"},
12+
{ "expression":"replace('QGIS ABC',array('A','B','C'),array('X','Y','Z'))", "returns":"'QGIS XYZ'"},
13+
{ "expression":"replace('QGIS',array('Q','S'),'')", "returns":"'GI'"} ] },
14+
{ "variant": "Map variant",
15+
"variant_description": "Returns a string with the supplied map keys replaced by paired values.",
16+
"arguments": [ {"arg":"string","description":"the input string"},
17+
{"arg":"map","description":"the map containing keys and values"} ],
18+
"examples": [ { "expression":"replace('APP SHOULD ROCK',map('APP','QGIS','SHOULD','DOES'))", "returns":"'QGIS DOES ROCK'"} ]
19+
}]
1220
}

‎src/core/qgsexpression.cpp

Lines changed: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,42 +1214,62 @@ static QVariant fcnLength( const QVariantList& values, const QgsExpressionContex
12141214

12151215
static QVariant fcnReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
12161216
{
1217-
QString str = getStringValue( values.at( 0 ), parent );
1218-
QVariantList before;
1219-
QVariantList after;
1220-
bool isSingleReplacement = false;
1221-
1222-
if ( values.at( 1 ).type() != QVariant::List && values.at( 2 ).type() != QVariant::StringList )
1217+
if ( values.count() == 2 && values.at( 1 ).type() == QVariant::Map )
12231218
{
1224-
before = QVariantList() << getStringValue( values.at( 1 ), parent );
1219+
QString str = getStringValue( values.at( 0 ), parent );
1220+
QVariantMap map = getMapValue( values.at( 1 ), parent );
1221+
1222+
for ( QVariantMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
1223+
{
1224+
str = str.replace( it.key(), it.value().toString() );
1225+
}
1226+
1227+
return QVariant( str );
12251228
}
1226-
else
1229+
else if ( values.count() == 3 )
12271230
{
1228-
before = getListValue( values.at( 1 ), parent );
1229-
}
1231+
QString str = getStringValue( values.at( 0 ), parent );
1232+
QVariantList before;
1233+
QVariantList after;
1234+
bool isSingleReplacement = false;
12301235

1231-
if ( values.at( 2 ).type() != QVariant::List && values.at( 2 ).type() != QVariant::StringList )
1232-
{
1233-
after = QVariantList() << getStringValue( values.at( 2 ), parent );
1234-
isSingleReplacement = true;
1236+
if ( values.at( 1 ).type() != QVariant::List && values.at( 2 ).type() != QVariant::StringList )
1237+
{
1238+
before = QVariantList() << getStringValue( values.at( 1 ), parent );
1239+
}
1240+
else
1241+
{
1242+
before = getListValue( values.at( 1 ), parent );
1243+
}
1244+
1245+
if ( values.at( 2 ).type() != QVariant::List && values.at( 2 ).type() != QVariant::StringList )
1246+
{
1247+
after = QVariantList() << getStringValue( values.at( 2 ), parent );
1248+
isSingleReplacement = true;
1249+
}
1250+
else
1251+
{
1252+
after = getListValue( values.at( 2 ), parent );
1253+
}
1254+
1255+
if ( !isSingleReplacement && before.length() != after.length() )
1256+
{
1257+
parent->setEvalErrorString( QObject::tr( "Invalid pair of array, length not identical" ) );
1258+
return QVariant();
1259+
}
1260+
1261+
for ( int i = 0; i < before.length(); i++ )
1262+
{
1263+
str = str.replace( before.at( i ).toString(), after.at( isSingleReplacement ? 0 : i ).toString() );
1264+
}
1265+
1266+
return QVariant( str );
12351267
}
12361268
else
12371269
{
1238-
after = getListValue( values.at( 2 ), parent );
1239-
}
1240-
1241-
if ( !isSingleReplacement && before.length() != after.length() )
1242-
{
1243-
parent->setEvalErrorString( QObject::tr( "Invalid pair of array, length not identical" ) );
1270+
parent->setEvalErrorString( QObject::tr( "Function replace requires 2 or 3 arguments" ) );
12441271
return QVariant();
12451272
}
1246-
1247-
for ( int i = 0; i < before.length(); i++ )
1248-
{
1249-
str = str.replace( before.at( i ).toString(), after.at( isSingleReplacement ? 0 : i ).toString() );
1250-
}
1251-
1252-
return QVariant( str );
12531273
}
12541274
static QVariant fcnRegexpReplace( const QVariantList& values, const QgsExpressionContext*, QgsExpression* parent )
12551275
{
@@ -3521,7 +3541,7 @@ const QList<QgsExpression::Function*>& QgsExpression::Functions()
35213541
<< new StaticFunction( QStringLiteral( "char" ), 1, fcnChar, QStringLiteral( "String" ) )
35223542
<< new StaticFunction( QStringLiteral( "wordwrap" ), ParameterList() << Parameter( QStringLiteral( "text" ) ) << Parameter( QStringLiteral( "length" ) ) << Parameter( QStringLiteral( "delimiter" ), true, "" ), fcnWordwrap, QStringLiteral( "String" ) )
35233543
<< new StaticFunction( QStringLiteral( "length" ), ParameterList() << Parameter( QStringLiteral( "text" ), true, "" ), fcnLength, QStringList() << QStringLiteral( "String" ) << QStringLiteral( "GeometryGroup" ) )
3524-
<< new StaticFunction( QStringLiteral( "replace" ), 3, fcnReplace, QStringLiteral( "String" ) )
3544+
<< new StaticFunction( QStringLiteral( "replace" ), -1, fcnReplace, QStringLiteral( "String" ) )
35253545
<< new StaticFunction( QStringLiteral( "regexp_replace" ), 3, fcnRegexpReplace, QStringLiteral( "String" ) )
35263546
<< new StaticFunction( QStringLiteral( "regexp_substr" ), 2, fcnRegexpSubstr, QStringLiteral( "String" ) )
35273547
<< new StaticFunction( QStringLiteral( "substr" ), 3, fcnSubstr, QStringLiteral( "String" ) )

‎tests/src/core/testqgsexpression.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,7 @@ class TestQgsExpression: public QObject
825825
QTest::newRow( "replace (array replaced by string)" ) << "replace('12345', array('2','4'), '')" << false << QVariant( "135" );
826826
QTest::newRow( "replace (unbalanced array, before > after)" ) << "replace('12345', array('1','2','3'), array('6','7'))" << true << QVariant();
827827
QTest::newRow( "replace (unbalanced array, before < after)" ) << "replace('12345', array('1','2'), array('6','7','8'))" << true << QVariant();
828+
QTest::newRow( "replace (map)" ) << "replace('APP SHOULD ROCK',map('APP','QGIS','SHOULD','DOES'))" << false << QVariant( "QGIS DOES ROCK" );
828829
QTest::newRow( "regexp_replace" ) << "regexp_replace('HeLLo','[eL]+', '-')" << false << QVariant( "H-o" );
829830
QTest::newRow( "regexp_replace greedy" ) << "regexp_replace('HeLLo','(?<=H).*L', '-')" << false << QVariant( "H-o" );
830831
QTest::newRow( "regexp_replace non greedy" ) << "regexp_replace('HeLLo','(?<=H).*?L', '-')" << false << QVariant( "H-Lo" );

0 commit comments

Comments
 (0)
Please sign in to comment.