Allow CPDecimal to handle decimal numbers with leading zeros

Without this fix, CPDecimal will return NaN for numbers that have leading zeros, e.g., 0123.

This fix changes the matching regex to allow leading zeros to pass. This is then converted to a proper number later on, e.g., "0123" => 123. This is in line with Cocoa behaviour.

This commit also includes updated unit tests.
This commit is contained in:
Andrew Hankinson
2013-03-07 00:26:02 -05:00
parent e2580bda05
commit 7bef84e4e9
3 changed files with 12 additions and 10 deletions
+2 -2
View File
@@ -108,7 +108,7 @@ function CPDecimalMakeWithString(string, locale)
// Regexp solution as found in JSON spec, with working regexp (I added groupings)
// Test here: http://www.regexplanet.com/simple/index.html
// Info from: http://stackoverflow.com/questions/638565/parsing-scientific-notation-sensibly
// ([+\-]?)((?:0|[1-9]\d*)) - integer part, cant have leading zeros
// ([+\-]?)((?:0|[0-9]\d*)) - integer part, can have leading zeros (follows Cocoa behaviour)
// (?:\.(\d*))? - optional decimal part plus number in group
// (?:[eE]([+\-]?)(\d+))? - optional exponent part plus number in group
// group 0: string, 1: sign, 2: integer, 3: decimal, 4: exponent sign, 5: exponent
@@ -116,7 +116,7 @@ function CPDecimalMakeWithString(string, locale)
// Note: this doesn't accept .01 for example, should it?
// If yes simply add '?' after integer part group, i.e. ([+\-]?)((?:0|[1-9]\d*)?)
// Note: now it accept .01 style.
var matches = string.match(/^([+\-]?)((?:0|[1-9]\d*)?)(?:\.(\d*))?(?:[eE]([+\-]?)(\d+))?$/);
var matches = string.match(/^([+\-]?)((?:0|[0-9]\d*)?)(?:\.(\d*))?(?:[eE]([+\-]?)(\d+))?$/);
if (!matches)
return CPDecimalMakeNaN();
+5 -5
View File
@@ -130,6 +130,9 @@
[self assert:[0] equals:dcm._mantissa message:"zero: - mantissa"];
[self assert:NO equals:dcm._isNegative message:"zero: - sign"];
// this is Cocoa behaviour -- convert a decimal number with a leading zero to a number.
dcmn = [[CPDecimalNumber alloc] initWithString:@"0123"];
[self assertTrue:[dcmn isEqualToNumber:123]];
// misc
// decimalValue <- if it hasnt been working so far, you would know.
@@ -147,14 +150,11 @@
dcmn = [[CPDecimalNumber alloc] initWithString:@"foo"];
[self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 2 overflow should return NaN"];
dcmn = [[CPDecimalNumber alloc] initWithString:@"0123"];
dcmn = [[CPDecimalNumber alloc] initWithString:@"1e200"];
[self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 3 overflow should return NaN"];
dcmn = [[CPDecimalNumber alloc] initWithString:@"1e200"];
[self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 4 overflow should return NaN"];
dcmn = [[CPDecimalNumber alloc] initWithString:@"12312e-23421"];
[self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 5 overflow should return NaN"];
[self assert:CPOrderedSame equals:[dcmn compare:[CPDecimalNumber notANumber]] message:"initWithString: 4 overflow should return NaN"];
}
- (void)testAdd
+5 -3
View File
@@ -68,7 +68,7 @@
[self assert:NO equals:dcm._isNaN message:"CPDecimalMakeWithString() Tf4: NaN is incorrectly set"];
dcm = CPDecimalMakeWithString(@"000000000000000000");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Tf5: Should be invalid"];
[self assertFalse:dcm._isNaN message:"CPDecimalMakeWithString() Tf5: Should be valid"];
// too large return NaN
dcm = CPDecimalMakeWithString(@"111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
@@ -95,10 +95,12 @@
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti7: catch of invalid number string. Should return NaN"];
dcm = CPDecimalMakeWithString(@"123ee");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti8: catch of invalid number string. Should return NaN"];
// this behaviour has changed to match Cocoa. Making a decimal with a leading zero should return the decimal.
dcm = CPDecimalMakeWithString(@"0001");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti9: catch of invalid number string. Should return NaN"];
[self assertFalse:dcm._isNaN message:"CPDecimalMakeWithString() Ti9: Numbers with leading zeros are valid numbers. Expected False when evaluating against NaN, got True."];
dcm = CPDecimalMakeWithString(@"-0001");
[self assertTrue:dcm._isNaN message:"CPDecimalMakeWithString() Ti10: catch of invalid number string. Should return NaN"];
[self assertFalse:dcm._isNaN message:"CPDecimalMakeWithString() Ti10: Numbers with leading zeros are valid numbers. Expected False when evaluating against NaN, got True."];
//test make with parts
dcm = CPDecimalMakeWithParts(10127658, 2);