Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looking for an universal way to parse price into decimal

I'm working on a project where I have to parse prices. I have to take into account different formats of prices.

Problems:

US citizens write prices this way: 1,000.00

EU this way: 1.000,00

This very problem could be solved splitting string using commas and dots so the last item in the list would be cents. The problem is that sometimes people doesn't write cents at all so somebody could write 1.000 EUR for example.

And there are other problems... sometimes people don't write dots at all.

Do you know some python module or function which could solve this problem and return decimal.Decimal of the price? I don't care about currency.

EDIT: Assume that I will have thousands of prices in such formats.

like image 740
Milano Avatar asked Dec 07 '16 17:12

Milano


People also ask

What is a string with digits only that parses successfully?

A string with digits only (which corresponds to the None style) always parses successfully if it is in the range of the Decimal type. The remaining NumberStyles members control elements that may be but are not required to be present in the input string.

How do I convert a cultureinfo input to a decimal value?

The NumberFormatInfo object that belongs to that CultureInfo object is then passed to the Parse (String, IFormatProvider) method to convert the user's input to a Decimal value.

How to parse a floating point value with thousands separators?

// Parse a floating point value with thousands separators value = "25,162.1378"; number = Decimal.Parse (value); Console.WriteLine ("' {0}' converted to {1}.", value, number); // Displays: // '25,162.1378' converted to 25162.1378.

Is the decimal number equivalent to the number contained in s?

The Decimal number equivalent to the number contained in s as specified by style and provider. s is not in the correct format. s represents a number less than Decimal.MinValue or greater than Decimal.MaxValue. s is null. style is not a NumberStyles value. style is the AllowHexSpecifier value.


2 Answers

This code uses this logic:

  • if no '.' or ',' are present, just convert to float
  • else if ',' or '.' are the 3rd character from the end, then this is the decimal character:

    . strip then non-decimal character, change the decimal char to '.' if necessary, then convert to float

  • else

    . there is no decimal part given, just strip all ',' and '.' and convert to float

This code is very dependent on getting valid strings - invalid strings like "1,2,3.000" or "1..." will give erroneous values.

def parse_price(s):
    if '.' not in s and ',' not in s:
        return float(s)

    elif s[-3] in ',.':
        dec_char = s[-3]
        sep_char = {'.': ',', ',':'.'}[dec_char]
        s = s.replace(sep_char, '')
        s = s.replace(',', '.')
        return float(s)

    else:
        s = s.replace(',','').replace('.', '')
        return float(s)

tests = """\
1.000
1.000,20
23.14
1,234
1.23
3,12
""".splitlines()
for test in tests:
    print(test, '->', parse_price(test))

gives

1.000 -> 1000.0
1.000,20 -> 1000.2
23.14 -> 23.14
1,234 -> 1234.0
1.23 -> 1.23
3,12 -> 3.12
like image 179
PaulMcG Avatar answered Nov 09 '22 23:11

PaulMcG


Use price-parser:

>>> from price_parser import parse_price
>>> parse_price('1,000.00')
Price(amount=Decimal('1000.00'), currency=None)
>>> parse_price('1.000,00')
Price(amount=Decimal('1000.00'), currency=None)
like image 24
Gallaecio Avatar answered Nov 10 '22 00:11

Gallaecio