Skip to content

Commit 85b9d37

Browse files
committed
Use QLocale to parse string representation of numbers
Because we now might have thousand separators, also fixes the NULL issue reported by DelazJ. Comes with many test cases.
1 parent cb3eb96 commit 85b9d37

File tree

2 files changed

+149
-10
lines changed

2 files changed

+149
-10
lines changed

src/core/qgsfield.cpp

+62-10
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,68 @@ bool QgsField::convertCompatible( QVariant &v ) const
277277
return false;
278278
}
279279

280+
// Give it a chance to convert to double since for not '.' locales
281+
// we accept both comma and dot as decimal point
282+
if ( d->type == QVariant::Double && v.type() == QVariant::String )
283+
{
284+
QVariant tmp( v );
285+
if ( !tmp.convert( d->type ) )
286+
{
287+
// This might be a string with thousand separator: use locale to convert
288+
bool ok;
289+
double d = QLocale().toDouble( v.toString(), &ok );
290+
if ( ok )
291+
{
292+
v = QVariant( d );
293+
return true;
294+
}
295+
// For not 'dot' locales, we also want to accept '.'
296+
if ( QLocale().decimalPoint() != '.' )
297+
{
298+
d = QLocale( QLocale::English ).toDouble( v.toString(), &ok );
299+
if ( ok )
300+
{
301+
v = QVariant( d );
302+
return true;
303+
}
304+
}
305+
}
306+
}
307+
308+
// For string representation of an int we also might have thousand separator
309+
if ( d->type == QVariant::Int && v.type() == QVariant::String )
310+
{
311+
QVariant tmp( v );
312+
if ( !tmp.convert( d->type ) )
313+
{
314+
// This might be a string with thousand separator: use locale to convert
315+
bool ok;
316+
int i = QLocale().toInt( v.toString(), &ok );
317+
if ( ok )
318+
{
319+
v = QVariant( i );
320+
return true;
321+
}
322+
}
323+
}
324+
325+
// For string representation of a long we also might have thousand separator
326+
if ( d->type == QVariant::LongLong && v.type() == QVariant::String )
327+
{
328+
QVariant tmp( v );
329+
if ( !tmp.convert( d->type ) )
330+
{
331+
// This might be a string with thousand separator: use locale to convert
332+
bool ok;
333+
qlonglong l = QLocale().toLongLong( v.toString(), &ok );
334+
if ( ok )
335+
{
336+
v = QVariant( l );
337+
return true;
338+
}
339+
}
340+
}
341+
280342
//String representations of doubles in QVariant will return false to convert( QVariant::Int )
281343
//work around this by first converting to double, and then checking whether the double is convertible to int
282344
if ( d->type == QVariant::Int && v.canConvert( QVariant::Double ) )
@@ -301,16 +363,6 @@ bool QgsField::convertCompatible( QVariant &v ) const
301363
return true;
302364
}
303365

304-
// Give it a chance to convert to double since for not '.' locales
305-
// we accept both comma and dot as decimal point
306-
if ( d->type == QVariant::Double && QLocale().decimalPoint() != '.' )
307-
{
308-
QVariant tmp( v );
309-
if ( d->type == QVariant::Double && !tmp.convert( d->type ) )
310-
{
311-
v = v.toString().replace( QLocale().decimalPoint(), '.' );
312-
}
313-
}
314366

315367
if ( !v.convert( d->type ) )
316368
{

tests/src/core/testqgsfield.cpp

+87
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,44 @@ void TestQgsField::convertCompatible()
498498
QCOMPARE( longlong.type(), QVariant::LongLong );
499499
QCOMPARE( longlong, QVariant( 99999999999999999LL ) );
500500

501+
//string representation of an int
502+
QVariant stringInt( "123456" );
503+
QVERIFY( intField.convertCompatible( stringInt ) );
504+
QCOMPARE( stringInt.type(), QVariant::Int );
505+
QCOMPARE( stringInt, QVariant( 123456 ) );
506+
// now with group separator for english locale
507+
stringInt = QVariant( "123,456" );
508+
QVERIFY( intField.convertCompatible( stringInt ) );
509+
QCOMPARE( stringInt.type(), QVariant::Int );
510+
QCOMPARE( stringInt, QVariant( "123456" ) );
511+
512+
//string representation of a longlong
513+
QVariant stringLong( "99999999999999999" );
514+
QVERIFY( longlongField.convertCompatible( stringLong ) );
515+
QCOMPARE( stringLong.type(), QVariant::LongLong );
516+
QCOMPARE( stringLong, QVariant( 99999999999999999LL ) );
517+
// now with group separator for english locale
518+
stringLong = QVariant( "99,999,999,999,999,999" );
519+
QVERIFY( longlongField.convertCompatible( stringLong ) );
520+
QCOMPARE( stringLong.type(), QVariant::LongLong );
521+
QCOMPARE( stringLong, QVariant( 99999999999999999LL ) );
522+
523+
524+
//string representation of a double
525+
QVariant stringDouble( "123456.012345" );
526+
QVERIFY( doubleField.convertCompatible( stringDouble ) );
527+
QCOMPARE( stringDouble.type(), QVariant::Double );
528+
QCOMPARE( stringDouble, QVariant( 123456.012345 ) );
529+
// now with group separator for english locale
530+
stringDouble = QVariant( "1,223,456.012345" );
531+
QVERIFY( doubleField.convertCompatible( stringDouble ) );
532+
QCOMPARE( stringDouble.type(), QVariant::Double );
533+
QCOMPARE( stringDouble, QVariant( 1223456.012345 ) );
534+
// This should not convert
535+
stringDouble = QVariant( "1.223.456,012345" );
536+
QVERIFY( ! doubleField.convertCompatible( stringDouble ) );
537+
538+
501539
//double with precision
502540
QgsField doubleWithPrecField( QStringLiteral( "double" ), QVariant::Double, QStringLiteral( "double" ), 10, 3 );
503541
doubleVar = QVariant( 10.12345678 );
@@ -513,12 +551,61 @@ void TestQgsField::convertCompatible()
513551
QCOMPARE( stringVar.type(), QVariant::String );
514552
QCOMPARE( stringVar.toString(), QString( "lon" ) );
515553

554+
555+
/////////////////////////////////////////////////////////
556+
// German locale tests
557+
516558
//double with ',' as decimal separator for German locale
517559
QLocale::setDefault( QLocale::German );
518560
QVariant doubleCommaVar( "1,2345" );
519561
QVERIFY( doubleField.convertCompatible( doubleCommaVar ) );
520562
QCOMPARE( doubleCommaVar.type(), QVariant::Double );
521563
QCOMPARE( doubleCommaVar.toString(), QString( "1.2345" ) );
564+
565+
//string representation of an int
566+
stringInt = QVariant( "123456" );
567+
QVERIFY( intField.convertCompatible( stringInt ) );
568+
QCOMPARE( stringInt.type(), QVariant::Int );
569+
QCOMPARE( stringInt, QVariant( 123456 ) );
570+
// now with group separator for german locale
571+
stringInt = QVariant( "123.456" );
572+
QVERIFY( intField.convertCompatible( stringInt ) );
573+
QCOMPARE( stringInt.type(), QVariant::Int );
574+
QCOMPARE( stringInt, QVariant( "123456" ) );
575+
576+
//string representation of a longlong
577+
stringLong = QVariant( "99999999999999999" );
578+
QVERIFY( longlongField.convertCompatible( stringLong ) );
579+
QCOMPARE( stringLong.type(), QVariant::LongLong );
580+
QCOMPARE( stringLong, QVariant( 99999999999999999LL ) );
581+
// now with group separator for german locale
582+
stringLong = QVariant( "99.999.999.999.999.999" );
583+
QVERIFY( longlongField.convertCompatible( stringLong ) );
584+
QCOMPARE( stringLong.type(), QVariant::LongLong );
585+
QCOMPARE( stringLong, QVariant( 99999999999999999LL ) );
586+
587+
//string representation of a double
588+
stringDouble = QVariant( "123456,012345" );
589+
QVERIFY( doubleField.convertCompatible( stringDouble ) );
590+
QCOMPARE( stringDouble.type(), QVariant::Double );
591+
QCOMPARE( stringDouble, QVariant( 123456.012345 ) );
592+
// For doubles we also want to accept dot as a decimal point
593+
stringDouble = QVariant( "123456.012345" );
594+
QVERIFY( doubleField.convertCompatible( stringDouble ) );
595+
QCOMPARE( stringDouble.type(), QVariant::Double );
596+
QCOMPARE( stringDouble, QVariant( 123456.012345 ) );
597+
// now with group separator for german locale
598+
stringDouble = QVariant( "1.223.456,012345" );
599+
QVERIFY( doubleField.convertCompatible( stringDouble ) );
600+
QCOMPARE( stringDouble.type(), QVariant::Double );
601+
QCOMPARE( stringDouble, QVariant( 1223456.012345 ) );
602+
// Be are good citizens and we also accept english locale
603+
stringDouble = QVariant( "1,223,456.012345" );
604+
QVERIFY( doubleField.convertCompatible( stringDouble ) );
605+
QCOMPARE( stringDouble.type(), QVariant::Double );
606+
QCOMPARE( stringDouble, QVariant( 1223456.012345 ) );
607+
608+
522609
}
523610

524611
void TestQgsField::dataStream()

0 commit comments

Comments
 (0)