NSScanner not scanning long numeric string into number - ios

I have a string "999999999999528106" and I am passing it to NSScanner but the output is not correct. I get 2147483647 as result.
I guess the big size of my string is not fitting into the NSInteger. Any clue
NSScanner *aScanner = [NSScanner scannerWithString:iString];
NSMutableCharacterSet *aCharset = [NSMutableCharacterSet whitespaceAndNewlineCharacterSet];
[aCharset formUnionWithCharacterSet:[NSCharacterSet symbolCharacterSet]];
[aScanner setCharactersToBeSkipped:[aCharset copy]];
NSInteger anIntegerResult = 0;
[aScanner setScanLocation:0];
if ([aScanner scanInteger:&anIntegerResult] && aScanner.isAtEnd)
return #(anIntegerResult);

From the NSScanner documentation:
Skips past excess digits in the case of overflow, so the receiver’s position is past the entire integer representation.
So yes, it's overflowing. You can use scanLongLong: instead.

Related

Objective C: Conversion of large hex to double gives wrong value

I have an issue converting a big hex number 0x500123fb2d414d3d1192a659d4d39dfd to its decimal value
double serialNumberValue = 0;
NSScanner * scanner = [NSScanner scannerWithString:#"0x500123fb2d414d3d1192a659d4d39dfd"];
[scanner scanHexDouble: &serialNumberValue];
NSString* serialNumber = [NSString stringWithFormat: #"%.f", serialNumberValue];
NSLog(#"serialNumber decimal value : %#", serialNumber);
The result I get is: 106344161744262488068834846534090620928 which corresponds to 0x500123FB2D414C000000000000000000 in hex
While the correct conversion is: 106344161744262493917718975250015952381
How can i solve this issue ?
FYI: I need the last 6 digits of the hexadecimal number in its decimal value.

Way to detect character that takes up more than one index spot in an NSString?

I'm wondering, is there a way to detect a character that takes up more than 1 index spot in an NSString? (like an emoji). I'm trying to implement a custom text view and when the user pushes delete, I need to know if I should delete only the previous one index spot or more.
Actually NSString use UTF-16.So it is quite difficult to work with characters which takes two UTF-16 charater(unichar) or more.But you can do with rangeOfComposedCharacterSequenceAtIndexto get range and than delete.
First find the last character index from string
NSUInteger lastCharIndex = [str length] - 1;
Than get the range of last character
NSRange lastCharRange = [str rangeOfComposedCharacterSequenceAtIndex: lastCharIndex];
Than delete with range from character (If it is of two UTF-16 than it deletes UTF-16)
deletedLastCharString = [str substringToIndex: lastCharRange.location];
You can use this method with any type of characters which takes any number of unichar
For one you could transform the string to a sequence of characters using [myString UTF8String] and you can then check if the character has its first bit set to one or zero. If its one then this is a UTF8 character and you can then check how many bytes are there to this character. Details about UTF8 can be found on Wikipedia - UTF8. Here is a simple example:
NSString *string = #"ČTest";
const char *str = [string UTF8String];
NSMutableString *ASCIIStr = [NSMutableString string];
for (int i = 0; i < strlen(str); ++i)
if (!(str[i] & 128))
[ASCIIStr appendFormat:#"%c", str[i]];
NSLog(#"%#", ASCIIStr); //Should contain only ASCII characters

How can I count decimal digits?

I have to count how many decimal digits are there in a double in Xcode 5. I know that I must convert my double in a NSString, but can you explain me how could I exactly do? Thanks
A significant problem is that a double has a fractional part which has no defined length. If you know you want, say, 3 fractional digits, you could do:
[[NSString stringWithFormat:#"%1.3f", theDoubleNumber] length]
There are more elegant ways, using modulo arithmetic or logarithms, but how elegant do you want to be?
A good method could be to take your double value and, for each iteration, increment a counter, multiply your value by ten, and constantly check if the left decimal part is really near from zero.
This could be a solution (referring to a previous code made by Graham Perks):
int countDigits(double num) {
int rv = 0;
const double insignificantDigit = 8;
double intpart, fracpart;
fracpart = modf(num, &intpart);
while ((fabs(fracpart) > 0.000000001f) && (rv < insignificantDigit))
{
num *= 10;
fracpart = modf(num, &intpart);
rv++;
}
return rv;
}
You could wrap the double in an instance of NSNumber and get an NSString representation from the NSNumber instance. From there, calculating the number of digits after the decimal could be done.
One possible way would be to implement a method that takes a double as an argument and returns an integer that represents the number of decimal places -
- (NSUInteger)decimalPlacesForDouble:(double)number {
// wrap double value in an instance of NSNumber
NSNumber *num = [NSNumber numberWithDouble:number];
// next make it a string
NSString *resultString = [num stringValue];
NSLog(#"result string is %#",resultString);
// scan to find how many chars we're not interested in
NSScanner *theScanner = [NSScanner scannerWithString:resultString];
NSString *decimalPoint = #".";
NSString *unwanted = nil;
[theScanner scanUpToString:decimalPoint intoString:&unwanted];
NSLog(#"unwanted is %#", unwanted);
// the number of decimals will be string length - unwanted length - 1
NSUInteger numDecimalPlaces = (([resultString length] - [unwanted length]) > 0) ? [resultString length] - [unwanted length] - 1 : 0;
return numDecimalPlaces;
}
Test the method with some code like this -
// test by changing double value here...
double testDouble = 1876.9999999999;
NSLog(#"number of decimals is %lu", (unsigned long)[self decimalPlacesForDouble:testDouble]);
results -
result string is 1876.9999999999
unwanted is 1876
number of decimals is 10
Depending on the value of the double, NSNumber may do some 'rounding trickery' so this method may or may not suit your requirements. It should be tested first with an approximate range of values that your implementation expects to determine if this approach is appropriate.

Extracting price from string

I am looking for a short and convenient way to extract a product's price from NSString.
I have tried regular expressions, but always found some cases where did not match.
The price can be any number including decimals, 0 and -1 (valid prices: 10, 10.99, -1, 0).
NSString can contain a string like: #"Prod. price: $10.99"
Thanks!
This will match all the examples you have given
-?\d+(\.\d{2})?
Optionally a -, followed by 1-many digits, optionally followed by a decimal point and 2 more digits.
If you've got other numbers that are not prices mixed in to the data then I don't think regex can fulfil your needs.
NSString *originalString = #"Prod. price: $10.99";
NSScanner *scanner = [NSScanner scannerWithString:originalString];
NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:#"-0123456789"];
[scanner scanUpToCharactersFromSet:numbers intoString:NULL];
double number;
[scanner scanDouble:&number];
number is equal to 10.99
Obviously if you have other numbers before the value you looking for you wont find it.
Assuming that your NSString will always contain the price with $ prep-ended to it, the following regex will match your need
.*?\$(-?(\d+)(.\d{1,2})?)
Once the above regex is matched you can find out match.group(1) to be the price from the NSString.

ios LINESTRING parsing

I have been planning the route as a custom in google maps for iOS.
How do I parsing the incoming JSON in LINESTRING??
My LINESTRING:
"coordInfo": "LINESTRING (28.646751729297 40.9993029074749, 28.6470087874434 40.9995465119554, 28.6470087874434 40.9995465119554, 28.6474633603416 41.0000088561426)"
},
It looks like, from what you posted, that objectForKey#"coordInfo" gives you a single string with numbers in parentheses. You could parse that using the NSString method componentsSeparatedByCharactersInSet: passing a set that contains left and right parentheses, comma, and space to produce an array of the individual number strings (as well as the word "LINESTRING" as the first string in the array). The array will also contain some empty strings where 2 separator characters are together (like comma and space), so you'll have to test for that when taking objects out of the array.
You could also use an NSScanner like this:
NSString *toParse = #"LINESTRING (28.646751729297 40.9993029074749, 28.6470087874434 40.9995465119554, 28.6470087874434 40.9995465119554, 28.6474633603416 41.0000088561426)";
NSScanner *scanner = [NSScanner scannerWithString:toParse];
double num;
while (! [scanner isAtEnd]) {
[scanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:nil];
[scanner scanDouble:&num];
// put numbers into an array here or use them somehow
NSLog(#"%f",num);
}

Resources