electronics-inventory/electronics_inventory/si.py

100 lines
2.7 KiB
Python

#!/usr/bin/env python3
import math
import re
import decimal
from typing import Set
si_table = {
-8: ("yocto", "y", "y", 10e-24),
-7: ("zepto", "z", "z", 10e-21),
-6: ("atto", "a", "a", 10e-18),
-5: ("femto", "f", "f", 10e-15),
-4: ("pico", "p", "p", 10e-12),
-3: ("nano", "n", "n", 10e-9),
-2: ("micro", "u", "μ", 10e-6),
-1: ("milli", "m", "m", 10e-3),
0: ("", "", "", 0),
1: ("kilo", "k", "k", 10e3),
2: ("mega", "M", "M", 10e6),
3: ("giga", "G", "G", 10e9),
4: ("tera", "T", "T", 10e12),
5: ("peta", "P", "P", 10e15),
6: ("exa", "E", "E", 10e18),
7: ("zetta", "Z", "Z", 10e21),
8: ("yotta", "Y", "Y", 10e24),
}
_si_letters_set: Set[str] = set()
for n in si_table:
_si_letters_set.add(si_table[n][1])
_si_letters_set.add(si_table[n][2])
si_letters = "".join(sorted(_si_letters_set))
def prefix_tuple(value, utf=True):
value = float(value)
ex = math.log(abs(value * 1.0000001), 10)
nex = math.floor(ex) // 3
nval = value / 10 ** (nex * 3)
if nex not in si_table:
raise ValueError("No suitable SI prefix found")
if utf == True:
px = si_table[nex][2]
else:
px = si_table[nex][1]
return (nval, px)
def prefix(value, utf=True, replace_separator=True):
v, px = prefix_tuple(value, utf)
if px == "":
return "{:1.2f}".format(v).rstrip("0").rstrip(".")
elif replace_separator == True:
s = "{:1.2f}".format(v).replace(".", px).rstrip("0").rstrip(".")
return s
else:
s = "{:1.2f}".format(v).rstrip("0").rstrip(".")
return s + " {:s}".format(px)
def power_by_prefix(string):
for v in si_table:
if string in si_table[v]:
return v
raise ValueError()
def decode_infix(string):
np = "^(([1-9][0-9]*)?[0-9](\.[0-9]+)?) ?([{:s}])?$".format(si_letters)
ni = "^(([1-9][0-9]*)?[0-9](([{:s}])[0-9]+)?)$".format(si_letters)
rp = re.match(np, string)
ri = re.match(ni, string)
if rp is not None:
if rp.groups()[3] is not None:
power = power_by_prefix(rp.groups()[3])
else:
power = 0
base = decimal.Decimal(rp.groups()[0])
return base * decimal.Decimal("10") ** (power * 3)
elif ri is not None:
base = decimal.Decimal(str(ri.groups()[0]).replace(ri.groups()[3], "."))
power = power_by_prefix(ri.groups()[3])
return base * decimal.Decimal("10") ** (power * 3)
else:
raise ValueError()
if __name__ == "__main__":
print(prefix(1.5632e11))
print(prefix(12.32e-9))
print(prefix(47000))
print(prefix(4700))
print(prefix(470))
print(si_letters)
print(decode_infix("0.23"))
print(decode_infix("470M"))
print(prefix(float(decode_infix("0k23"))))