-1

I need to append 0, 1, or 2 0s to a string, depends on its decimal separator, so that

  • "100", "100." and "100.0" becomes "100.00"
  • "100.8" becomes "100.80"
  • "100.85" remains unchanged

I could find the decimal separator and check its distance to end endIndex of the string, but is there an easier way of doing it?

NumberFormatter does this, but the actual string I have, isn't a plain number that can go through a formatter.

For example:

let amount = "123,456,789"

then formatted amount should be "123,456,789.00"

assumption:

the given string has at most one decimal separator with at most two decimal places

So there can't be string like: "123.4.4.5"

Also I want to use the decimal separator from NumberFormatter().decimalSeparator

Heuristic
  • 5,087
  • 9
  • 54
  • 94

2 Answers2

1

You could pass the string through a decimal formatter to get the underlying number, and then back again through the formatter to get a formatted string:

let amount = "123,456,789"
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
let number = formatter.number(from: amount)
let newAmountString = formatter.string(from: number!)  //"123,456,789.00"

(You should check that number is not nil before force unwrapping it, with if letor guard)

You could wrap this in a function:

func zeroPadding(toString: String) -> String? {
    let formatter = NumberFormatter()
    formatter.numberStyle = .decimal
    formatter.maximumFractionDigits = 2
    formatter.minimumFractionDigits = 2
    guard let number = formatter.number(from: toString) else {
        return nil
    }
    return formatter.string(from: number)
}

Here are some test cases:

zeroPadding(toString: "123,456,789")         //"123,456,789.00"
zeroPadding(toString: "123,456,789.0")       //"123,456,789.00"
zeroPadding(toString: "123,456,789.10")      //"123,456,789.10"
zeroPadding(toString: "123,456,789.123")     //"123,456,789.12"
zeroPadding(toString: "123.4567")            //"123.46"
zeroPadding(toString: "Price: 1€ for a ")  //nil

Or define it as an extension on String:

extension String {
    func withZeroPadding() -> String? {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        formatter.maximumFractionDigits = 2
        formatter.minimumFractionDigits = 2
        guard let number = formatter.number(from: self) else {
            return nil
        }
        return formatter.string(from: number)
    }
}

And use it like this:

"123.4.4.5".withZeroPadding()    //nil 
"12.".withZeroPadding()          //"12.00"
"123,456,789".withZeroPadding()  //"123,456,789.00"
ielyamani
  • 17,807
  • 10
  • 55
  • 90
0

This is the following code snippet I have tested on Playground, it can be achieved more smartly but for now it is working.

//let amount = "123,456,789.545222323"
//let amount = "123,456,789."
let amount = "123,456,789"
let removeSpaces = amount.replacingOccurrences(of: " ", with: "")


if removeSpaces.count > 0
{
let arrSTR = removeSpaces.components(separatedBy: ".")
if  arrSTR.count > 1
{
    var strAfterDecimal = arrSTR[1]
    if strAfterDecimal.count >= 2
    {
        strAfterDecimal = strAfterDecimal[0..<2]
    }else if strAfterDecimal.count != 0
    {
        strAfterDecimal = "\(strAfterDecimal)0"
    }else
    {
        strAfterDecimal = "00"
    }
    let finalSTR = String("\(arrSTR[0]).\(strAfterDecimal)")
    print("Final with Decimal - \(finalSTR)")
}else
{
    let finalSTR = String(arrSTR[0] + ".00")
    print("Final without Decimal - \(finalSTR)")
}
}

extension String {
subscript(_ range: CountableRange<Int>) -> String {
    let idx1 = index(startIndex, offsetBy: max(0, range.lowerBound))
    let idx2 = index(startIndex, offsetBy: min(self.count, range.upperBound))
    return String(self[idx1..<idx2])
}
}
Manish Pathak
  • 3,224
  • 1
  • 18
  • 22