2

In IOS SWIFT 4, I am trying to create a Decimal out of a given String for Money calculations considering the Current Locale (Mainly considering Decimal Separator & GroupingSeparator)

Just tried to use Decimal initialization with Locale, BUT as explains in this link if the string contains a non-numeric character, it just reads up to that character rather than providing nil. So I wouldn't know if the string has successfully converted to Decimal or partially considered. e.g In following case if the number string (stringValue) has grouping separator it just reads until up to that character (which is comma). So following code provides answer as 1.

let stringValue: String = "1,200.00"
let decValue: Decimal = Decimal(string: stringValue, locale: Locale(identifier: "en_GB")) // ANSWER - 1

That's the problem with Decimal Initialisation. I can resolve that grouping separator problem with NumberFormatter as follows but decimalValue property in converted NSNumber is providing wrong value.

let stringValue: String = "8.20"
let nf = NumberFormatter()
nf.locale = Locale(identifier: "en_GB")
nf.usesGroupingSeparator = true
nf.numberStyle = NumberFormatter.Style.decimal
if let number = nf.number(from: stringValue)
{
    let decValue: Decimal = number.decimalValue  // ANSWER: 8.199999999999999
}

I have seen this was discussed many places but haven't seen a fully resolved answer. Would like to hear what the best way to convert a given String value to it's Decimal number considering the Locale. (If german / French - group separator is "." and Decimal separator is "," etc)

JibW
  • 4,538
  • 17
  • 66
  • 101

1 Answers1

2

Try this :

let stringValue: String = "8.20"

let loc = Locale(identifier: "en_GB")

let nf = NumberFormatter()
nf.locale = loc
nf.usesGroupingSeparator = true
nf.numberStyle = .decimal

var decValue: Decimal? = nil

if let _ = nf.number(from: stringValue) {

    var copy = stringValue

    if let sep = loc.groupingSeparator {
        copy = copy.split(separator: Character(sep)).joined()
    }

    decValue = Decimal(string: copy, locale: loc)
}

And you could check the result this way :

decValue.map { print($0) }  //8.2
ielyamani
  • 17,807
  • 10
  • 55
  • 90
  • 1
    Hi Carpsen90, Thanks for the answer and this will take care of the grouping separator..... But the problem is I wouldn't know if theDecimal initialization have considered my full string or it has considered part of it in cases where it receive an invalid decimal string. For e.g Decimal(string: "12.45d2") ---> Answer 12.45, rather than getting NIL in these cases….. What else has to consider etc is a problem. Needs to be sure of this as this going to do money calculations. – JibW Mar 04 '19 at 07:01