iOS: formatting decimal numbers - iphone

I have an NSDecimalNumber representing a money amount.
I want to print it as "999 999 999 999 999 999,00", regardless on the locale.
How do I do that?
NSNumberFormatter prints me 1 000 000 000 000 000 000,00 instead (it seems Apple engineers never designed the iPhone to be a platform for financial software).
[NSDecimalNumber description] and [NSDecimalNumber descriptionWithLocale] both print correct value. How can I format the result, with grouping separator set to #"\u2006", decimal separator to #"**,**", and exactly 2 decimal digits after the decimal seperator?
Thanks in advance!
Update:
Here's my solution, 10x to Sulthan:
#implementation NSDecimalNumber(MiscUtils)
-(NSString*)moneyToString
{
static NSDecimalNumberHandler* s_handler = nil;
if( !s_handler )
s_handler = [ [ NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:2 raiseOnExactness:NO raiseOnOverflow:NO raiseOnUnderflow:NO raiseOnDivideByZero:NO ] retain ];
NSDecimalNumber *dec = [ self decimalNumberByRoundingAccordingToBehavior:s_handler ];
NSString* str = [ dec description ];
NSRange rDot = [ str rangeOfString:#"." ];
int nIntDigits = str.length;
int nFracDigits = 0;
if( rDot.length > 0 )
{
nIntDigits = rDot.location;
nFracDigits = str.length - ( rDot.location + 1 );
}
int nGroupSeparators = ( nIntDigits - 1 ) / 3;
NSMutableString* res = [ NSMutableString stringWithCapacity:nIntDigits + nGroupSeparators + 3 ];
NSString *groupingSeparator = #"\u2006";
int nFirstGroup = ( nIntDigits % 3 );
int nextInd = 0;
if( nFirstGroup )
{
[ res appendString:[ str substringToIndex:nFirstGroup ] ];
nextInd = nFirstGroup;
}
while( nextInd < nIntDigits )
{
if( res.length > 0 )
[ res appendString:groupingSeparator ];
[ res appendString:[ str substringWithRange:NSMakeRange( nextInd, 3 ) ] ];
nextInd += 3;
}
if( nFracDigits > 0 )
{
if( nFracDigits > 2 )
nFracDigits = 2;
[ res appendString:#"," ];
[ res appendString:[ str substringWithRange:NSMakeRange( rDot.location + 1, nFracDigits ) ] ];
while( nFracDigits < 2 )
{
[ res appendString:#"0" ];
nFracDigits++;
}
}
else
[ res appendString:#",00" ];
// DLog( "formatDecimal: %# -> %#", dec, res );
return res;
}
#end

Try this:
NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"US"];
NSNumberFormatter *frm = [[NSNumberFormatter alloc] init];
[frm setNumberStyle:NSNumberFormatterDecimalStyle];
[frm setMaximumFractionDigits:2];
[frm setMinimumFractionDigits:2];
[frm setLocale:usLocale];
NSString *formattedNumberStr = [frm stringFromNumber:[NSNumber numberWithFloat:floatToRound]];
[frm release];
[usLocale release];
return formattedNumberStr;

I had the same problem. I was told that NSNumberFormatter converts everything to a double first. How did I solve it? It's easy, just write your own formatter.
First round the decimal to 2 decimal digits.
Get its description as a string.
Find decimal point (.) in the string and replace it with the one you want.
After every three digits from the decimal point to the left, insert a grouping separator.

Related

handle JSON response in project

I am a new programmer. I get the following response from server. How can i get the value of 0 index "Mile High Motors of Butte" and "Mile High Motors of Dillion" from following
Thanks
{
dealer = (
{
0 = "Mile High Motors of Butte";
1 = "3883 Harrison";
2 = Butte;
3 = 59701;
4 = MT;
5 = "http://www.buttesmilehighchryslerjeepdodge.com";
6 = 2;
7 = 0;
address = "3883 Harrison";
city = Butte;
distance = 0;
id = 2;
name = "Mile High Motors of Butte";
state = MT;
url = "http://www.buttesmilehighchryslerjeepdodge.com";
zip = 59701;
},
{
0 = "Mile High Motors of Dillon";
1 = "790 N Montana St";
2 = Dillon;
3 = 59725;
4 = Montana;
5 = "http://www.MileHighDillon.com";
6 = 13;
7 = "60.1235269593172";
address = "790 N Montana St";
city = Dillon;
distance = "60.1235269593172";
id = 13;
name = "Mile High Motors of Dillon";
state = Montana;
url = "http://www.MileHighDillon.com";
zip = 59725;
}
);
success = 1;
}
Okay let's see your structure (assuming that you have already deserialized your JSON string).
You have an NSDictionary with two keys (dealer & success). Now dealer key is an NSArray with two NSDictionaries. So based on that we could do:
NSDictionary *myJson; // Assuming that this is what you have posted
NSArray *dealers = [myJson valueForKey:#"dealer"];
// Now just grab whatever you need
NSString *dealerOne = [[dealers objectAtIndex:0] valueForKey:#"0"]; //Mile High Motors of Butte
NSString *dealerTwo = [[dealers objectAtIndex:1] valueForKey:#"0"]; //Mile High Motors of Dillon
Or you could just iterate your dealers array like this:
for (NSDictionary *dealer in dealers)
{
NSString *dealerName = [dealer valueForKey:#"0"];
// Do something useful
}
NSMutableArray yourStringArray= [[NSMutableArray alloc] init]; //for getting texts what you want.
NSArray * array1 = [yourDictionary valueForKey:#"dealer"];// You will get array which has dictionary elements.
for (NSDictionary *dealer in array1)// Write loop for getting your string.
{
NSString *dealerName = [dealer valueForKey:#"0"];
[yourStringArray addObject:dealerName];
}
I think it will be helpful to you.

How retrireve array from dictionary

I have 2 columns in my Sqlite table 1.DetailsID & 2.Detailstype
i have stored values id: int and detailstype :varchar.
set the id with string in sqlite select query as
while(sqlite3_step(selectPrefer) == SQLITE_ROW)
{
NSString *detailsString = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectPrefer, 1)];
int detailsId = (int)sqlite3_column_int(selectPrefer, 0);
[detailsData setObject:detailsString forKey:[NSNumber numberWithInt:detailsId ]];
}
I have a NSmutable dictionary like this:
(
0 = "˚F";
12 = Activity;
11 = BM;
7 = "Heart Rate";
6 = "Nose Problem";
2 = Rx;
1 = BP;
10 = Food;
9 = "Stress Level";
8 = Glucose;
5 = "Pain Level";
4 = Weight;
3 = Events;
}
i can get arrays using allKeys & allValues but these are not in order
Now i want seperate arrays like
{
0
1
2
3
4
5
6
7
8
9
10
11
12
)
both values & keys In ascending order with respect to keys
(
"˚F";
Activity;
BM;
"Heart Rate";
"Nose Problem";
Rx;
BP;
Food;
"Stress Level";
Glucose;
"Pain Level";
Weight;
Events;
)
with out any modifications in sqlite query
- what to do thannks in advance
You should use the allKeys and allValues property of the dictionay :
allKeys Returns a new array containing the dictionary’s keys.
allValues Returns a new array containing the dictionary’s values.
Try this :
NSArray *keysArray = [yourDictionnay allKeys];
NSArray *valuesArray = [yourDictionnay allvalues];
Hope this helps,
Vincent
you need both allValues and allkeys.
NSArray *values = [dictionary allValues];
NSArray *keys = [dicitoary allKeys];

Format a String in IPhone

I need to add space after every 4 characters in a string.. For example if the string is aaaaaaaa, i need to format it as aaaa aaaa. I tried the following code, but it doesn't work for me.
NSMutableString *currentFormattedString = [[NSMutableString alloc] initWithString:formattedString];
int count = [formattedString length];
for (int i = 0; i<count; i++) {
if ( i %4 == 0) {
[currentFormattedString insertString:#" " atIndex:i];
}
}
Can anyone help me with this?
You haven't said what isn't working with your code, so it's hard to know exactly what to answer. As a tip - in future questions don't just say "it isn't working", but state WHAT isn't working and HOW it isn't working. However...
NSMutableString *currentFormattedString = [[NSMutableString alloc] initWithString:formattedString];
int count = [formattedString length];
for (int i = 0; i<count; i++) {
if ( i %4 == 0) {
[currentFormattedString insertString:#" " atIndex:i];
}
}
You are inserting a space, but you are not then accounting for this in your index value. So, suppose your formattedString is aaaaaaaaaaaaaaaa
The first time through your loop, you will get to the 4th position and insert a space at i=4
aaaa aaaaaaaaaaaa
Now the next time you get to insert a space, i will be 8. But the 8th position in your currentFormattedString isn't where you think it will be
aaaa aaa aaaaaaaaa
Next time it will be another 4 characters along which still isn't where you think
aaaa aaa aa aaaaaaa
And so on
You have to take into account the inserted space which will affect the offset value.
NSString *text = [[NSString alloc] initWithString:#"aaaaaaaa"];
NSString *result = [[NSString alloc] init];
double count = text.length/4;
if (count>1) {
for (int i = 0; i<count; i++) {
result = [NSString stringWithFormat:#"%#%# ",result,[text substringWithRange:NSMakeRange(i*4, 4)]];
}
result = [NSString stringWithFormat:#"%#%# ",result,[text substringWithRange:NSMakeRange(((int)count)*4, text.length-((int)count)*4)]];
}
else result = text;
I found the following which formats a string to a telephone number format, but it looks like you could easily change it to support other formats
Telephone number string formatting
Nick Bull answered on the reasons why your method broke already.
IMHO the appropriate solution would be to use a while loop and do the loop increments yourself.
NSInteger i = 4; // first #" " should be inserted after the 4th (index = 3) char
while (i < count) {
[currentFormattedString insertString:#" " atIndex:i];
count ++; // you did insert #" " so the length of the string increased
i += 5; // you now must skip 5 (" 1234") characters
}

How to convert a float to an Int by rounding to the nearest whole integer

Is there a way to convert a float to an Int by rounding to the nearest possible whole integer?
To round to the nearest use roundf(), to round up use ceilf(), to round down use floorf(). Hopefully this example demonstrates...
#import "math.h"
...
float numberToRound;
int result;
numberToRound = 4.51;
result = (int)roundf(numberToRound);
NSLog(#"roundf(%f) = %d", numberToRound, result); // roundf(4.510000) = 5
result = (int)ceilf(numberToRound);
NSLog(#"ceilf(%f) = %d", numberToRound, result); // ceilf(4.510000) = 5
result = (int)floorf(numberToRound);
NSLog(#"floorf(%f) = %d", numberToRound, result); // floorf(4.510000) = 4
numberToRound = 10.49;
result = (int)roundf(numberToRound);
NSLog(#"roundf(%f) = %d", numberToRound, result); // roundf(10.490000) = 10
result = (int)ceilf(numberToRound);
NSLog(#"ceilf(%f) = %d", numberToRound, result); // ceilf(10.490000) = 11
result = (int)floorf(numberToRound);
NSLog(#"floorf(%f) = %d", numberToRound, result); // floorf(10.490000) = 10
numberToRound = -2.49;
result = (int)roundf(numberToRound);
NSLog(#"roundf(%f) = %d", numberToRound, result); // roundf(-2.490000) = -2
result = (int)ceilf(numberToRound);
NSLog(#"ceilf(%f) = %d", numberToRound, result); // ceilf(-2.490000) = -2
result = (int)floorf(numberToRound);
NSLog(#"floorf(%f) = %d", numberToRound, result); // floorf(-2.490000) = -3
numberToRound = -3.51;
result = (int)roundf(numberToRound);
NSLog(#"roundf(%f) = %d", numberToRound, result); // roundf(-3.510000) = -4
result = (int)ceilf(numberToRound);
NSLog(#"ceilf(%f) = %d", numberToRound, result); // ceilf(-3.510000) = -3
result = (int)floorf(numberToRound);
NSLog(#"floorf(%f) = %d", numberToRound, result); // floorf(-3.510000) = -4
The documentation...
https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/roundf.3.html
https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/ceil.3.html
https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/floor.3.html
Actually Paul Beckingham's answer isn't quite correct. If you try a negative number like -1.51, you get -1 instead of -2.
The functions round(), roundf(), lround(), and lroundf() from math.h work for negative numbers too.
How about this:
float f = 1.51;
int i = (int) (f + 0.5);
round() can round a float to nearest int, but it's output is still a float... so cast round()'s output to an integer:
float input = 3.456;
int result;
result = (int)round(input);
//result is: 3
Working example for C++ here.
(int)floor(f+0.5);
Try this...

How to sort a string of characters in objective-C?

I'm looking for an Objective-C way of sorting characters in a string, as per the answer to this question.
Ideally a function that takes an NSString and returns the sorted equivalent.
Additionally I'd like to run length encode sequences of 3 or more repeats. So, for example "mississippi" first becomes "iiiimppssss", and then could be shortened by encoding as "4impp4s".
I'm not expert in Objective-C (more Java and C++ background) so I'd also like some clue as to what is the best practice for dealing with the memory management (retain counts etc - no GC on the iphone) for the return value of such a function. My source string is in an iPhone search bar control and so is an NSString *.
int char_compare(const char* a, const char* b) {
if(*a < *b) {
return -1;
} else if(*a > *b) {
return 1;
} else {
return 0;
}
}
NSString *sort_str(NSString *unsorted) {
int len = [unsorted length] + 1;
char *cstr = malloc(len);
[unsorted getCString:cstr maxLength:len encoding:NSISOLatin1StringEncoding];
qsort(cstr, len - 1, sizeof(char), char_compare);
NSString *sorted = [NSString stringWithCString:cstr encoding:NSISOLatin1StringEncoding];
free(cstr);
return sorted;
}
The return value is autoreleased so if you want to hold on to it in the caller you'll need to retain it. Not Unicode safe.
With a bounded code-set, radix sort is best:
NSString * sortString(NSString* word) {
int rads[128];
const char *cstr = [word UTF8String];
char *buff = calloc([word length]+1, sizeof(char));
int p = 0;
for(int c = 'a'; c <= 'z'; c++) {
rads[c] = 0;
}
for(int k = 0; k < [word length]; k++) {
int c = cstr[k];
rads[c]++;
}
for(int c = 'a'; c <= 'z'; c++) {
int n = rads[c];
while (n > 0) {
buff[p++] = c;
n--;
}
}
buff[p++] = 0;
return [NSString stringWithUTF8String: buff];
}
Note that the example above only works for lowercase letters (copied from a specific app which needs to sort lowercase strings). To expand it to handle all of the ASCII 127, just do for(c=0; c <= 127; c++).