Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I force a sign-character on the output of an NSNumberFormatter

I want to use a number formatter to generate my output, so the number is automatically formatted for the user's locale, but I want it to work like "%+.1f" does in printf(), that is always have a sign specified.

NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
nf.numberStyle = NSNumberFormatterDecimalStyle;
nf.maximumFractionDigits = 1;

double val = 3.1234;
label.text = [NSString stringWithFormat: @"XXX %@ XXX", [nf stringFromNumber: [NSNumber numberWithDouble: val]]];

I want the label to come out "XXX +3.1 XXX" in the US and the appropriate but equivalent string for any other location. The only things I can find are setPositiveFormat: and setPositivePrefix:.

But I don't want to set the format since I don't know how to format numbers in other countries; I don't know if a plus-sign is used to designate a positive number in Arabic or Russian or some culture I have not thought of. I do know, for example, that decimal points, commas, spaces, etc., all have different meanings in European countries compared to the U.S. - Could the same be true for +/- signs?

What I do currently is:

label.text = [NSString stringWithFormat: @"XXX %s%@ XXX", (val < 0) ? "" : "+",
    [nf stringFromNumber: [NSNumber numberWithDouble: val]]];

But this presumes that '+' and '-' are correct for all formats.

I'm sure it must be there since it is a standard formatting thing that has been in printf() since the dark ages...

like image 357
LavaSlider Avatar asked Jan 04 '13 01:01

LavaSlider


4 Answers

How about this:

NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
nf.numberStyle = NSNumberFormatterDecimalStyle;
nf.maximumFractionDigits = 1;

double val = 3.1234;
NSString *sign = (val < 0) ? [nf minusSign] : [nf plusSign];
NSString *num = [nf stringFromNumber:@(abs(val))]; // avoid double negative
label.text = [NSString stringWithFormat: @"XXX %@%@ XXX", sign, num];

You may need to check to see if num has the sign prefix or not so it isn't shown twice.

Edit: After some playing around, it has been determined, for the "Decimal" style, that no current locale uses a positivePrefix. No current locale uses a plusSign other than the standard + character. No current locale uses a negativePrefix that is different than minusSign. No current locale uses either positiveSuffix or negativeSuffix.

So an easier approach would be to do:

NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
nf.numberStyle = NSNumberFormatterDecimalStyle;
nf.maximumFractionDigits = 1;
[nf setPositivePrefix:[nf plusSign]];
[nf setNegativePrefix:[nf minusSign]];

label.text = [nf stringFromNumber:@(val)];
like image 165
rmaddy Avatar answered Nov 12 '22 01:11

rmaddy


This case it's simple, just add the prefix:

nf.positivePrefix= nf.plusSign;
like image 28
Ramy Al Zuhouri Avatar answered Nov 12 '22 01:11

Ramy Al Zuhouri


Though it won't use the user's locale, you can do the following to generate the +/- sign without the somewhat expensive overhead of an NSNumberFormatter:

// assume 'number' is an NSNumber
label.text = [NSString stringWithFormat:@"%+.02f", [number floatValue]];
like image 3
Brian Sachetta Avatar answered Nov 12 '22 00:11

Brian Sachetta


Simple Case:

    let f = NumberFormatter()
    f.positivePrefix = f.plusSign

Currency Case :

Hack needed, because setting the prefix to plusSign only will remove the currency symbol.

    let f = NumberFormatter()
    f.numberStyle = .currency
    f.positivePrefix = f.plusSign + f.currencySymbol

There is a bit more work depending on the locale.. The currency symbol may be before, or after, but this is probably another subject..

Edit:

Even if it is another subject, I'd say a possible solution to the problem above is to subclass NSNumberFormatter :

override func string(from number: NSNumber) -> String? {
    returns ( number.doubleValue >= 0 ? super.plusSign : "" ) + super.string(from: number)
}

This way, NSNumberFormatter should manage the currency position while your subclass simply prepend the + sign. No time to test this in depth, but at least it is an approach.

like image 3
Moose Avatar answered Nov 12 '22 01:11

Moose