Custom locale configuration for float conversion

前端 未结 3 1583
滥情空心
滥情空心 2021-02-19 22:43

I need to convert a string in the format \"1.234.345,00\" to the float value 1234345.00.

One way is to use repeated str.repl

3条回答
  •  没有蜡笔的小新
    2021-02-19 23:24

    Here's something, using Babel, that works for me.

    First you feed it some test data, with your expectations and it builds a dictionary of separator to locale alias that fits.

    Then you can convert from that point on.

    import string
    from decimal import Decimal
    from babel.numbers import parse_decimal, NumberFormatError
    from babel.core import UnknownLocaleError
    import locale
    
    traindata = [
        ("1.234.345,00", Decimal("1234345.00")),
        ("1,234,345.00", Decimal("1234345.00")),
        ("345", Decimal("345.00")),
    ]
    
    data = traindata + [
        ("345,00", Decimal("345.00")),
        ("345.00", Decimal("345.00")),
        ("746", Decimal("746.00")),
    ]
    
    def findseps(input_):
        #you need to have no separator 
        #or at least a decimal separator for this to work...
    
        seps = [c for c in input_ if not c in string.digits]
        if not seps:
            return ""
    
        sep = seps[-1]
        #if the decimal is something then thousand will be the other...
        seps = "." + sep if sep == "," else "," + sep
        return seps 
    
    
    def setup(input_, exp, lookup):
    
    
        key = findseps(input_)
    
        if key in lookup:
            return
    
        for alias in locale.locale_alias:
            #print(alias)
    
            try:
                got = parse_decimal(input_, locale=alias)
            except (NumberFormatError,UnknownLocaleError, ValueError) as e:
                continue
            except (Exception,) as e:
                raise
            if exp == got:
                lookup[key] = alias
                return
    
    
    def convert(input_, lookup):
        seps = findseps(input_)
        try:
            locale_ = lookup[seps]
            convert.locale_ = locale_
        except (KeyError,) as e:
            convert.locale_ = None
            return "unexpected seps:%s" % seps
    
        try:
            return parse_decimal(input_, locale=locale_)
        except (Exception,) as e:
            return e
    
    
    lookup = {}
    
    #train your data
    for input_, exp in traindata:
        setup(input_, exp, lookup)
    
    #once it's trained you know which locales to use
    print(data)
    
    
    for input_, exp in data:
        got = convert(input_, lookup)
    
        # print (input_)
        msg = "%s => %s with local:%s:" % (input_, got, convert.locale_)
        if exp == got:
            print("\n  success : " + msg)
        else:
            print("\n  failure : " + msg)
    
    print(lookup)
    

    output:

    [('1.234.345,00', Decimal('1234345.00')), ('1,234,345.00', Decimal('1234345.00')), ('345', Decimal('345.00')), ('345,00', Decimal('345.00')), ('345.00', Decimal('345.00')), ('746', Decimal('746.00'))]
    
      success : 1.234.345,00 => 1234345.00 with local:is_is:
    
      success : 1,234,345.00 => 1234345.00 with local:ko_kr.euc:
    
      success : 345 => 345 with local:ko_kr.euc:
    
      success : 345,00 => 345.00 with local:is_is:
    
      success : 345.00 => 345.00 with local:ko_kr.euc:
    
      success : 746 => 746 with local:ko_kr.euc:
    {',.': 'ko_kr.euc', '': 'ko_kr.euc', '.,': 'is_is'}
    

提交回复
热议问题