Last active
May 15, 2021 23:01
-
-
Save RavuAlHemio/7d1dcb7fe42e90e851f026ef87787320 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# released under CC0: https://creativecommons.org/publicdomain/zero/1.0/ | |
from decimal import Decimal | |
DEFAULT_TOLERANCE = "20" | |
COLOR_ALIASES = { | |
# alternative names/spellings | |
"grey": "gray", | |
"purple": "violet", | |
# shortcuts | |
# (black/blue/brown is annoying) | |
"pk": "pink", | |
"s": "silver", | |
"gd": "gold", | |
"bk": "black", | |
"br": "brown", | |
"bn": "brown", | |
"r": "red", | |
"o": "orange", | |
"y": "yellow", | |
"gn": "green", | |
"bu": "blue", | |
"be": "blue", | |
"v": "violet", | |
"pu": "violet", # purple | |
"gy": "gray", | |
"w": "white", | |
} | |
IMPRECISE_COLOR_ALIASES = { | |
"b": 'use "bk" for black, "br" or "bn" for brown, "bu" or "be" for blue', | |
"g": 'use "gn" for green, "gy" for gray, "gd" for gold', | |
"p": 'use "pu" for purple (or "v" for violet), "pk" for pink', | |
} | |
COLOR_TO_DIGIT = { | |
"black": 0, | |
"brown": 1, | |
"red": 2, | |
"orange": 3, | |
"yellow": 4, | |
"green": 5, | |
"blue": 6, | |
"violet": 7, | |
"gray": 8, | |
"white": 9, | |
} | |
COLOR_TO_POWER = { | |
"pink": -3, | |
"silver": -2, | |
"gold": -1, | |
"black": 0, | |
"brown": 1, | |
"red": 2, | |
"orange": 3, | |
"yellow": 4, | |
"green": 5, | |
"blue": 6, | |
"violet": 7, | |
"gray": 8, | |
"white": 9, | |
} | |
COLOR_TO_TOLERANCE = { | |
"silver": "10", | |
"gold": "5", | |
"brown": "1", | |
"red": "2", | |
"orange": "0.05", | |
"yellow": "0.02", | |
"green": "0.5", | |
"blue": "0.25", | |
"violet": "0.1", | |
"gray": "0.01", | |
} | |
INDEX_TO_BAND_ORDINAL = [ | |
"1st", | |
"2nd", | |
"3rd", | |
"4th", | |
"5th", | |
] | |
SI_PREFIXES_POSITIVE = ["", "k", "M", "G", "T", "P", "E", "Z", "Y"] | |
SI_PREFIXES_NEGATIVE = ["", "m", "μ", "n", "p", "f", "a", "z", "y"] | |
def decode_resistor(spec: str) -> str: | |
# lowercase the input, split on spaces (removing empty words) | |
spec = spec.lower() | |
colors = [color for color in spec.split(" ") if color] | |
# map color aliases to their canonical name | |
for i, color in enumerate(colors): | |
unaliased_color = COLOR_ALIASES.get(color, None) | |
if unaliased_color is not None: | |
colors[i] = unaliased_color | |
continue | |
annoyed_message = IMPRECISE_COLOR_ALIASES.get(color, None) | |
if annoyed_message is not None: | |
raise ValueError(annoyed_message) | |
# ensure correct count (also handle single black band) | |
if len(colors) == 1 and colors[0] == "black": | |
return "0 Ω" | |
if len(colors) not in (4, 5): | |
raise ValueError("need 4 or 5 colors, got {0}".format(len(colors))) | |
# assemble the digits | |
value = Decimal(0) | |
for i, color in enumerate(colors[:-2]): | |
try: | |
digit = COLOR_TO_DIGIT[color] | |
except KeyError as ex: | |
msg = "{0} band (digit) has unknown color {1}".format( | |
INDEX_TO_BAND_ORDINAL[i], repr(color) | |
) | |
raise ValueError(msg) from ex | |
value *= Decimal(10) | |
value += Decimal(digit) | |
# multiply by the power of 10 | |
try: | |
power = COLOR_TO_POWER[colors[-2]] | |
except KeyError as ex: | |
i = len(colors) - 2 | |
msg = "{0} band (multiplier) has unknown color {1}".format( | |
INDEX_TO_BAND_ORDINAL[i], repr(colors[-2]) | |
) | |
raise ValueError(msg) from ex | |
value *= Decimal(10) ** Decimal(power) | |
# get tolerance | |
try: | |
tolerance = COLOR_TO_TOLERANCE[colors[-1]] | |
except KeyError as ex: | |
i = len(colors) - 1 | |
msg = "{0} band (tolerance) has unknown color {1}".format( | |
INDEX_TO_BAND_ORDINAL[i], repr(colors[-1]) | |
) | |
raise ValueError(msg) from ex | |
# simplify to the nearest SI prefix | |
si_prefix = 0 | |
if not value.is_zero: | |
thousand = Decimal(1000) | |
thousandth = Decimal("0.001") | |
while value >= thousand: | |
value /= thousand | |
si_prefix += 1 | |
while value <= thousandth: | |
value *= thousand | |
si_prefix -= 1 | |
# assemble the final text | |
return "{0} {1}Ω (± {2}%)".format( | |
value, | |
SI_PREFIXES_POSITIVE[si_prefix] if si_prefix >= 0 else SI_PREFIXES_NEGATIVE[-si_prefix], | |
tolerance, | |
) | |
if __name__ == "__main__": | |
import sys | |
for color_string in sys.argv[1:]: | |
try: | |
decoded = decode_resistor(color_string) | |
except ValueError as ex: | |
decoded = ex.args[0] | |
print("{0}: {1}".format(color_string, decoded)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment