-4

I'm facing a problem with formatting a double variable in iOS Swift

The variables that I have are like for instance 0.7, -4.56, 34.6 but they should be in the format 00.70, -04.56, 34.60

What's the best way to approach that?

rmaddy
  • 314,917
  • 42
  • 532
  • 579
Codetard
  • 2,441
  • 28
  • 34

4 Answers4

2

Checkout this

extension Double {
    func formatNumber(minimumIntegerDigits: Int, minimumFractionDigits: Int, maximumFractionDigits: Int=2) -> String {
        let numberFormatter = NumberFormatter()
        numberFormatter.numberStyle = .decimal
        numberFormatter.minimumIntegerDigits = minimumIntegerDigits
        numberFormatter.minimumFractionDigits = minimumFractionDigits
        numberFormatter.maximumFractionDigits = maximumFractionDigits

        return numberFormatter.string(for: self) ?? ""
    }
}

999.989.formatNumber(minimumIntegerDigits: 2, minimumFractionDigits: 2) // => 999.99
9.989.formatNumber(minimumIntegerDigits: 2, minimumFractionDigits: 2) // => 09.99
Satish
  • 2,015
  • 1
  • 14
  • 22
  • 2
    maximumFractionDigits & minimumFractionDigits both?? I think one needs to be IntegerDigits there. – iOSer Sep 27 '18 at 11:40
  • @Sh_Khan `NumberFormatter ` require `NSNumber` `open func string(from number: NSNumber) -> String?` – Satish Sep 27 '18 at 11:40
  • `return numberFormatter.string(for: self) ?? ""` – Leo Dabus Sep 27 '18 at 11:57
  • 1
    @iOSer - yes, you are right, answer updated – Satish Sep 27 '18 at 11:58
  • 1
    Note that this approach will create a new number formatter each time this method is called. You should declare your number formatter as a static property on Formatter – Leo Dabus Sep 27 '18 at 11:58
  • @LeoDabus - I won't agree with you on declaring static property all times, by using this approach you will end up declearing everything as static. – Satish Sep 27 '18 at 12:03
  • https://stackoverflow.com/questions/25339936/swift-double-to-string/27705739?s=1|80.8182#27705739 – Leo Dabus Sep 27 '18 at 12:04
  • No need to create a NSNumber object from your Double. Did you read my other comment above? – Leo Dabus Sep 27 '18 at 12:13
  • Awesomeness! Saved my day ;) – Codetard Sep 27 '18 at 13:31
  • This answer does not produce the output it claims. The results are `999.989` and `09.989`. You would also need to set `maximumFractionDigits`. – rmaddy Oct 06 '18 at 22:02
  • @rmaddy updated, thanks :) – Satish Oct 08 '18 at 05:45
  • That update will cause problems if the user passes a value of `3` or more to the `minimumFractionDigits` parameter. – rmaddy Oct 08 '18 at 13:58
  • @rmaddy we are here to guide and share ideas on how things can be used. The person using it can tweak according to his/her need. – Satish Oct 09 '18 at 05:56
  • And the most up voted and accepted answer should not be edited afterward with bugs. The answer should remain worthy of being up voted and accepted by continuing to be correct. – rmaddy Oct 09 '18 at 14:20
0

Use a NumberFormatter like so:

let number = 0.7

let numberFormatter = NumberFormatter()

numberFormatter.minimumIntegerDigits = 2

numberFormatter.maximumFractionDigits = 2
numberFormatter.minimumFractionDigits = 2

numberFormatter.string(for: number)

Or have it defined as a function:

func format(_ x: Double) -> String? {
    guard abs(x) < 100 else {
        print("The argument must have 2 integer digits at maximum")
        return nil
    }

    let numberFormatter = NumberFormatter()

    numberFormatter.maximumIntegerDigits = 2
    numberFormatter.minimumIntegerDigits = 2

    numberFormatter.maximumFractionDigits = 2
    numberFormatter.minimumFractionDigits = 2

    return numberFormatter.string(for: x)
}

format(-0.7)  //"-00.70"
format(120)   //nil , and prints "The argument must have 2 integer digits at maximum" 

Remember that the method Formatter.string(for:) returns an optional string.

As pointed out by @LeoDabus, to avoid creating a new Number Formatter each time this function is called, we can define a static property on NumberFormatter:

extension NumberFormatter {
    static let formatter_2Int_2Frac: NumberFormatter = {
        let numberFormatter = NumberFormatter()
        numberFormatter.maximumIntegerDigits = 2
        numberFormatter.minimumIntegerDigits = 2

        numberFormatter.maximumFractionDigits = 2
        numberFormatter.minimumFractionDigits = 2
        return numberFormatter
    }()
}

And thus, the function above will look like this:

func format(_ x: Double) -> String? {
    guard abs(x) < 100 else {
        print("The argument must have 2 integer digits at maximum")
        return nil
    }
    return NumberFormatter.formatter_2Int_2Frac.string(for: x)
}
ielyamani
  • 17,807
  • 10
  • 55
  • 90
  • May be `%02.2f`? – Cy-4AH Sep 27 '18 at 11:31
  • 1
    @Cy-4AH though %02.2f would work! This is more correct way of achieving the same. – iOSer Sep 27 '18 at 11:42
  • you should use Formatter's method `string(for: Any)` and pass a Double – Leo Dabus Sep 27 '18 at 12:01
  • 1
    @LeoDabus cool I've updated the answer – ielyamani Sep 27 '18 at 12:08
  • @LeoDabus I've adopted your suggestion of having an extension on NumberFormatter – ielyamani Sep 27 '18 at 12:20
  • @Carpsen90 make it a property on `Formatter` and name it `number`. When calling it `Formatter.number.whatever` Note that it is a class so even declaring it as constant, its properties still can be changed. If you need a DateFormatter declare it there also, name it date and so on. You can group all your project formatters there. – Leo Dabus Sep 27 '18 at 12:48
0

Another option

let f = NumberFormatter()

f.minimumFractionDigits = 2

f.minimumIntegerDigits = 2

let str = f.string(from:-4.6)

print(str) // -04.60
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
0
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
numberFormatter.minimumIntegerDigits = 2
numberFormatter.minimumFractionDigits = 2

let formattedNumbers = [0.7, -4.56, 34.6].flatMap { number in
    return numberFormatter.string(for: number)
}
print(formattedNumbers) //prints ["00.70", "-04.56", "34.60"]
iOSer
  • 2,241
  • 1
  • 18
  • 26