[expressions] Re-permit format_number to omit group separators

After 6fcef30cc50, group separators were always included in the
results from format_number (even if a locale which doesn't use
them like the 'C' locale is specified). 6fcef30cc50 was added
to fix an old regression, but in doing so we lost flexibility
to skip unwanted separators.

Workaround this by introducing a new opt-in omit_group_separators
argument for format_number to skip the thousand separators when
desired. Also add an opt-in trim_trailing_zeroes argument for
further flexibility.
This commit is contained in:
Nyall Dawson 2023-02-07 11:41:55 +10:00
parent 87ab2b8c0a
commit 49adde6b9a
3 changed files with 51 additions and 3 deletions

View File

@ -15,6 +15,16 @@
"arg": "language",
"optional": true,
"description": "language (lowercase, two- or three-letter, <a href='https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes'>ISO 639 language code</a>) used to format the number into a string. By default the current QGIS user locale is used."
}, {
"arg": "omit_group_separators",
"optional": true,
"default": "false",
"description": "if set to true then group separators will not be included in the string"
}, {
"arg": "trim_trailing_zeroes",
"optional": true,
"default": "false",
"description": "if set to true then trailing zeros following the decimal point will be trimmed from the string"
}],
"examples": [{
"expression": "format_number(10000000.332,2)",

View File

@ -5628,9 +5628,36 @@ static QVariant fcnFormatNumber( const QVariantList &values, const QgsExpression
return QVariant();
}
const bool omitGroupSeparator = values.value( 3 ).toBool();
const bool trimTrailingZeros = values.value( 4 ).toBool();
QLocale locale = !language.isEmpty() ? QLocale( language ) : QLocale();
locale.setNumberOptions( locale.numberOptions() &= ~QLocale::NumberOption::OmitGroupSeparator );
return locale.toString( value, 'f', places );
if ( !omitGroupSeparator )
locale.setNumberOptions( locale.numberOptions() & ~QLocale::NumberOption::OmitGroupSeparator );
else
locale.setNumberOptions( locale.numberOptions() | QLocale::NumberOption::OmitGroupSeparator );
QString res = locale.toString( value, 'f', places );
if ( trimTrailingZeros )
{
const QChar decimal = locale.decimalPoint();
const QChar zeroDigit = locale.zeroDigit();
if ( res.contains( decimal ) )
{
int trimPoint = res.length() - 1;
while ( res.at( trimPoint ) == zeroDigit )
trimPoint--;
if ( res.at( trimPoint ) == decimal )
trimPoint--;
res.truncate( trimPoint + 1 );
}
}
return res;
}
static QVariant fcnFormatDate( const QVariantList &values, const QgsExpressionContext *, QgsExpression *parent, const QgsExpressionNodeFunction * )
@ -8133,7 +8160,12 @@ const QList<QgsExpressionFunction *> &QgsExpression::Functions()
<< new QgsStaticExpressionFunction( QStringLiteral( "rpad" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "width" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "fill" ) ), fcnRPad, QStringLiteral( "String" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "lpad" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "string" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "width" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "fill" ) ), fcnLPad, QStringLiteral( "String" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "format" ), -1, fcnFormatString, QStringLiteral( "String" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "format_number" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "number" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "places" ), true, 0 ) << QgsExpressionFunction::Parameter( QStringLiteral( "language" ), true, QVariant() ), fcnFormatNumber, QStringLiteral( "String" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "format_number" ), QgsExpressionFunction::ParameterList()
<< QgsExpressionFunction::Parameter( QStringLiteral( "number" ) )
<< QgsExpressionFunction::Parameter( QStringLiteral( "places" ), true, 0 )
<< QgsExpressionFunction::Parameter( QStringLiteral( "language" ), true, QVariant() )
<< QgsExpressionFunction::Parameter( QStringLiteral( "omit_group_separators" ), true, false )
<< QgsExpressionFunction::Parameter( QStringLiteral( "trim_trailing_zeroes" ), true, false ), fcnFormatNumber, QStringLiteral( "String" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "format_date" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "datetime" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "format" ) ) << QgsExpressionFunction::Parameter( QStringLiteral( "language" ), true, QVariant() ), fcnFormatDate, QStringList() << QStringLiteral( "String" ) << QStringLiteral( "Date and Time" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "color_grayscale_average" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color" ) ), fcnColorGrayscaleAverage, QStringLiteral( "Color" ) )
<< new QgsStaticExpressionFunction( QStringLiteral( "color_mix_rgb" ), QgsExpressionFunction::ParameterList() << QgsExpressionFunction::Parameter( QStringLiteral( "color1" ) )

View File

@ -1625,6 +1625,12 @@ class TestQgsExpression: public QObject
QTest::newRow( "format_number large" ) << "format_number(9000000.0,0)" << false << QVariant( "9,000,000" );
QTest::newRow( "format_number many decimals" ) << "format_number(123.45600,4)" << false << QVariant( "123.4560" );
QTest::newRow( "format_number no decimals" ) << "format_number(1999.567,0)" << false << QVariant( "2,000" );
QTest::newRow( "format_number omit group separator" ) << "format_number(1002999.567,0,omit_group_separators:=true)" << false << QVariant( "1003000" );
QTest::newRow( "format_number omit group separator small" ) << "format_number(999,0,omit_group_separators:=true)" << false << QVariant( "999" );
QTest::newRow( "format_number trim trailing zeros" ) << "format_number(123.45600,4,trim_trailing_zeroes:=true)" << false << QVariant( "123.456" );
QTest::newRow( "format_number trim trailing zeros none" ) << "format_number(123.45600,2,trim_trailing_zeroes:=true)" << false << QVariant( "123.46" );
QTest::newRow( "format_number trim trailing zeros many" ) << "format_number(123.45600,10,trim_trailing_zeroes:=true)" << false << QVariant( "123.456" );
QTest::newRow( "format_number trim trailing zeros no decimal" ) << "format_number(123,0,trim_trailing_zeroes:=true)" << false << QVariant( "123" );
QTest::newRow( "format_number language parameter" ) << "format_number(123457.00,2,'fr')" << false << QVariant( "123\u202F457,00" );
QTest::newRow( "lower" ) << "lower('HeLLo')" << false << QVariant( "hello" );
QTest::newRow( "upper" ) << "upper('HeLLo')" << false << QVariant( "HELLO" );