LavaSlider
LavaSlider

Reputation: 2504

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...

Upvotes: 16

Views: 8485

Answers (7)

Gabriel Gomes
Gabriel Gomes

Reputation: 101

I don't think any of the previous answers will actually take into consideration everything you mentioned in your question.

It is true that NumberFormatter does not have an option to set the plus sign visible for all positive numbers when formatting currency values.

Also, replacing prefixes and suffixes will likely break the format for some regions and always replacing a prefix will only work if the set locale uses the currency symbol on the left.

A simple way to address this without losing the locale formatting can be seen below:

var value: Double = 3.1234
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.maximumFractionDigits = 1

if value > 0 {
    return formatter.string(for: value.negated())?.replacingOccurrences(
            of: formatter.minusSign,
            with: formatter.plusSign
        )
} else {
    return formatter.string(for: value)
}

Even though this can be seen as hack, it's an effective way to achieve everything you mentioned without manually writing a number formatter.

Upvotes: 0

Moose
Moose

Reputation: 2737

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.

Upvotes: 3

lifeisfoo
lifeisfoo

Reputation: 16294

A reusable formatter in swift:

var numberFormatter: NSNumberFormatter {
    let formatter = NSNumberFormatter()
    formatter.numberStyle = .DecimalStyle
    formatter.locale = NSLocale(localeIdentifier: "it_IT")//your Locale
    formatter.maximumFractionDigits = 2
    formatter.minimumFractionDigits = 0
    formatter.positivePrefix = formatter.plusSign
    return formatter
}

Then use it:

let myDoubleValue = 12.00
let myStringNumber = numberFormatter.stringFromNumber(myDoubleValue)!

Upvotes: 0

Brian Sachetta
Brian Sachetta

Reputation: 3463

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]];

Upvotes: 3

rmaddy
rmaddy

Reputation: 318774

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)];

Upvotes: 21

Ramy Al Zuhouri
Ramy Al Zuhouri

Reputation: 21966

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

nf.positivePrefix= nf.plusSign;

Upvotes: 15

jscs
jscs

Reputation: 64002

The underlying formatting language for NSNumberFormatter doesn't have any provision for what you want to do -- it will allow you to specify a localized positive sign on exponents, but not for the entire formatted string. Nor does NSLocale seem to make available the localized positive sign.

Aside from making a dummy string that includes an exponent, pulling the localized positive sign out, and putting your final formatted string together by hand, I think you're out of luck.

Upvotes: 0

Related Questions