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?
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"