Home > Software design >  Convert string currency to float with ruby
Convert string currency to float with ruby

Time:10-29

I have the following string:

"1.273,08"

And I need to convert to float and the result must be:

1273.08

I tried some code using gsub but I can't solve this. How can I do this conversion?

CodePudding user response:

I would do

"1.273,08".delete('.')   # delete '.' from the string  
          .tr(',', '.')  # replace ',' with '.'
          .to_f          # translate to float
#=> 1273.08

CodePudding user response:

You have already received two good answers how to massage your String into your desired format using String#delete and String#tr.

But there is a deeper problem.

The decimal value 1 273.0810 cannot be accurately represented as an IEEE 754-2019 / ISO/IEC 60559:2020 binary64 floating point value.

Just like the value 1/3rd can easily be represented in ternary (0.13) but has an infinite representation in decimal (0.33333333…10, i.e. 0.[3]…10) and thus cannot be accurately represented, the value 8/100th can easily be represented in decimal (0.0810) but has an infinite representation in binary (0.0001010001111010111000010100011110101110000101…2, i.e. 0.[00010100011110101110]…2). In other words, it is impossible to express 1 273.0810 as a Ruby Float.

And that's not specific to Ruby, or even to programming, that is just basic high school maths: you cannot represent this number in binary, period, just like you cannot represent 1/3rd in decimal, or π in any integer base.

And of course, computers don't have infinite memory, so not only does 1 273.0810 have an infinite representation in binary, but as a Float, it will also be cut off after 64 bits. The closest possible value to 1 273.0810 as an IEEE 754-2019 / ISO/IEC 60559:2020 binary64 floating point value is 1 273.079 999 999 999 927 240 423 858 1710, which is less than 1 273.0810.

That is why you should never represent money using binary numbers: everybody will expect it to be decimal, not binary; if I write a cheque, I write it in decimal, not binary. People will expect that it is impossible to represent $ 1/3rd, they will expect that it is impossible to represent $ π, but they will not expect and not accept that if they put $ 1273.08 into their account, they will actually end up with slightly less than that.

The correct way to represent money would be to use a specialized Money datatype, or at least using the bigdecimal library from the standard library:

require 'bigdecimal'

BigDecimal('1.273,08'.delete('.').tr(',', '.'))
#=> 0.127308e4

CodePudding user response:

So, we're using . as a thousands separator and , instead of a dot:

str = "1.273,08"
str.gsub('.','').gsub(',', '.').to_f
  •  Tags:  
  • ruby
  • Related