0

I have a string that always converted into something like this where the user inputs a number and always starting in the decimal places,

So I have 0.01 -> 0.10 -> 1.00

but I don't want something like that, I want to convert only what the user has typed

here's my existing code that convert 100000 into 1,000.00

func convertme(string: String) -> String{
    var number: NSNumber!
    let formatter = NumberFormatter()
    formatter.numberStyle = .currencyAccounting
    formatter.currencySymbol = ""
    formatter.maximumFractionDigits = 2
    formatter.minimumFractionDigits = 2

    var amountWithPrefix = string

    // remove from String: "$", ".", ","
    let regex = try! NSRegularExpression(pattern: "[^0-9]", options: .caseInsensitive)
    amountWithPrefix = regex.stringByReplacingMatches(in: amountWithPrefix, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, string.count), withTemplate: "")
    
    print("amountWithPrefix", amountWithPrefix)

    let double = (amountWithPrefix as NSString).doubleValue
    number = NSNumber(value: (double / 100))

    // if first number is 0 or all numbers were deleted
    guard number != 0 as NSNumber else {
        return ""
    }

    return formatter.string(from: number)!
}

expected result:

I want to to format the number on the string without adding additional data, I want to turn (100000. into 100,000.) (100000.0 into 100,000.0

I want my 100000 be converted into 100,000, and only going to have a decimal if the user inputed a decimal too, so when the user inputted 100000.00 it will be converted into 100,000.00.

PS. I have a regex there that accepts only number but not the decimal, how can I make it also accept decimal?

Dylan
  • 1,121
  • 1
  • 13
  • 28
  • @LeoDabus no it's not, I already explained on the question why my expected output is not the same as that link. I showed it in my existing code and the output was the answer in the link you gave. – Dylan Sep 15 '20 at 04:47

1 Answers1

1

You can simply filter non digits or periods from the original string, try to coerce the resulting string to integer. If successful set the formatter maximum fraction digits to zero otherwise set the maximum fraction digits to 2 and coerce the string to double:

extension Formatter {
    static let currency: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.locale = .init(identifier: "en_US_POSIX")
        formatter.numberStyle = .currencyAccounting
        formatter.currencySymbol = ""
        return formatter
    }()
}

extension Numeric {
    var currencyUS: String {
         Formatter.currency.string(for: self) ?? ""
    }
}

func convertme(string: String) -> String {
    let string = string.filter("0123456789.".contains)
    if let integer = Int(string)  {
        Formatter.currency.maximumFractionDigits = 0
        return Formatter.currency.string(for: integer) ?? "0"
    }
    Formatter.currency.maximumFractionDigits = 2
    return Double(string)?.currencyUS ?? "0"
}

convertme(string: "100000")     // "100,000"
convertme(string: "100000.00")  // "100,000.00"


edit/update: "100,000." it is not a valid number format. You would need to manually insert your period at the end of the string.

func convertme(string: String) -> String {
    var string = string.filter("0123456789.".contains)
    // this makes sure there is only one period and keep only the last one in the string
    while let firstIndex = string.firstIndex(of: "."),
          let _ = string[firstIndex...].dropFirst().firstIndex(of: ".") {
        string.remove(at: firstIndex)
    }
    // get the index of the period in your string
    if let index = string.firstIndex(of: ".") {
        // get the fraction digits count and set the number formatter appropriately
        let fractionDigits = string[index...].dropFirst().count
        Formatter.currency.minimumFractionDigits = fractionDigits
        Formatter.currency.maximumFractionDigits = fractionDigits
        // Number Formatter wont add a period at the end of the string if there is no fractional digits then you need to manually add it yourself
        if fractionDigits == 0 {
            return (Double(string)?.currencyUS ?? "0") + "."
        }
    } else {
        // in case there is no period set the fraction digits to zero
        Formatter.currency.minimumFractionDigits = 0
        Formatter.currency.maximumFractionDigits = 0
    }
    return Double(string)?.currencyUS ?? "0"
}

Playground Testing:

convertme(string: "100000")      // "100,000"
convertme(string: "100000.")     // "100,000."
convertme(string: "100000.0")    // "100,000.0"
convertme(string: "100000.00")   // "100,000.00"
convertme(string: "100000.000")  // "100,000.000"
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • the user types `convertme(string: "100000.")` it was converted to 100,000.00, what I mean in my expected output was convert only what the user typed, so when the user typed 100000. it should be converted to 100,000. – Dylan Sep 15 '20 at 09:24