Project

General

Profile

1
# Value to string conversion
2
# This file's encoding must be UTF-8Y with BOM so Python will auto-detect UTF-8
3

    
4
import locale
5
import re
6

    
7
import strings
8
import util
9

    
10
locale.setlocale(locale.LC_ALL, '') # needed to initialize locale
11

    
12
##### String parsing
13

    
14
def clean_numeric(val):
15
    '''Removes embedded whitespace. e.g "1, 000"'''
16
    return re.sub(r'(?<=[,.]) +', r'', val)
17

    
18
def str2int(val): return locale.atoi(clean_numeric(val))
19

    
20
def str2float(val): return locale.atof(clean_numeric(val))
21

    
22
##### Value formatting
23

    
24
def format_str(format, val):
25
    return locale.format_string(format, val, grouping=True)
26

    
27
def int2str(val): return format_str('%d', val)
28

    
29
def float2str(val): return format_str('%f', val)
30

    
31
def to_percent(val, sig_figs=2):
32
    if val >= 1: sig_figs += 1
33
    return format_str('%#.'+str(sig_figs)+'g', val*100)+'%'
34

    
35
def to_si(val, sig_figs=3):
36
    '''Adds SI prefix to value'''
37
    prefix = ''
38
    if val < 1: prefix = 'm'; val *= 1000
39
    return format_str('%#.'+str(sig_figs)+'g', val)+' '+prefix
40

    
41
##### Units
42

    
43
class MissingUnitsException(Exception):
44
    def __init__(self, value):
45
        Exception.__init__(self, 'Value has no units: '+value)
46

    
47
def std_units(units):
48
    if units == None: return units
49
    else: return strings.remove_suffix('.', units) # for abbr ending in '.'
50
    # TODO: deal with '"° and abbrs
51

    
52
def parse_units(value):
53
    '''@return tuple (number float, units str|None)'''
54
    number = value
55
    units = None
56
    if not value.isdigit(): # optimization to avoid regexp for simple cases
57
        match = re.match(ur'(?i)^\s*(.*?\d\.?)\s*([a-z\'"°][\w.*/^-]*?)?\s*$',
58
            value)
59
        if match: # has units
60
            number, units = match.groups()
61
            units = std_units(util.none_if(units, u''))
62
    return (str2float(number), units)
63

    
64
def cleanup_units(value, default_units=None):
65
    '''Cleans up units so the number is separated from the units by one space.
66
    @param default_units Units to add if value has no units. If None, raises
67
        MissingUnitsException if value has no units.
68
    '''
69
    number, units = parse_units(value)
70
    if units == None:
71
        if default_units != None: units = default_units
72
        else: raise MissingUnitsException(value)
73
    return str(number)+' '+units
(7-7/18)