Last active
November 6, 2016 06:19
-
-
Save fourohfour/f0d9660081525640b1249f5f104f02e6 to your computer and use it in GitHub Desktop.
Currency Convertor
This file contains 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
from urllib.request import urlopen, build_opener | |
import html | |
## User Interface Layer | |
class InputtedValue: | |
def __init__(self, code, quantity = 1.0): | |
self.code = code | |
self.quantity = quantity | |
class CurrencyConvertorApp: | |
def discern_value(self, tokens): | |
quantity_candidates = [] | |
for token in tokens: | |
try: | |
float(token) | |
except ValueError: | |
continue | |
else: | |
quantity_candidates.append(token) | |
code_candidates = {token : len(tokens) - tokens.index(token) for token in tokens} | |
code_candidates = {token : score for token, score in code_candidates.items() if len(token) is 3} | |
code_candidates = {token : score for token, score in code_candidates.items() if token not in quantity_candidates} | |
if not code_candidates: | |
return (False, "No currency codes could be found in: " + " ".join(tokens)) | |
for token in code_candidates: | |
if token == token.upper(): | |
code_candidates[token] += 5 | |
if quantity_candidates: | |
distance = abs(tokens.index(quantity_candidates[0]) - tokens.index(token)) | |
code_candidates[token] += distance | |
code = max(code_candidates, key = (lambda token: code_candidates[token])) | |
if not quantity_candidates: | |
return (True, InputtedValue(code)) | |
else: | |
return (True, InputtedValue(code, float(quantity_candidates[0]))) | |
def prompt(self): | |
command = input(">>> ") | |
tokens = [t.strip() for t in command.split()] | |
pivots = ["to", "into", "in-to", "as", "in"] | |
pivot_index = -1 | |
for pivot in pivots: | |
if pivot in tokens: | |
pivot_index = tokens.index(pivot) | |
if pivot_index is -1: | |
print("The structure of this conversion command is unintelligable.") | |
return | |
first_value = self.discern_value(tokens[:pivot_index]) | |
second_value = self.discern_value(tokens[pivot_index:]) | |
if not first_value[0]: | |
print(first_value[1]) | |
return | |
if not second_value[0]: | |
print(second_value[1]) | |
return | |
first_cur = Currency.create(first_value[1].code) | |
second_cur = Currency.create(second_value[1].code) | |
quantity = first_value[1].quantity | |
print("Converting : " + str(first_cur) + " => " + str(second_cur)) | |
print(("Quantity : %.2f " + first_cur.code) % quantity) | |
result = first_cur.convertor(second_cur).convert(quantity) | |
print(("%.2f " + first_cur.code + " is %.2f " + second_cur.code) % (quantity, result)) | |
def main(self): | |
print("⌜-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-⌝") | |
print("|Currency Convertor Application!|") | |
print("⌞-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-⌟") | |
print(" Example: convert 10 GBP to EUR ") | |
while True: | |
print() | |
try: | |
self.prompt() | |
except KeyboardInterrupt: | |
print() | |
return | |
## Abstract Layer | |
class Convertor: | |
def __init__(self, a, b): | |
self.a = a | |
self.b = b | |
def convert(self, quantity): | |
if self.a.unusable or self.b.unusable: | |
return 0.0 | |
base = self.a.value * quantity | |
as_b = base / self.b.value | |
return as_b | |
class Currency: | |
@staticmethod | |
def create(code): | |
try: | |
return get_currency(code) | |
except BadCurrency: | |
return Currency("???", "?", 0.0, unusable = True) | |
def __init__(self, code, symbol, value, unusable = False): | |
self.code = code | |
self.symbol = symbol | |
self.value = value | |
self.unusable = unusable | |
def __str__(self): | |
return self.code + " (" + self.symbol + ") : " + str(self.value) + (" [UNUSABLE]" * int(self.unusable)) | |
def convertor(self, other_currency): | |
return Convertor(self, other_currency) | |
## Value Layer | |
class FailedGrab(Exception): | |
pass | |
def grab_end(string, sub): | |
if string.find(sub) == -1: | |
raise FailedGrab() | |
string = string[string.find(sub) + len(sub):] | |
return string | |
def grab_start(string, sub): | |
if string.find(sub) == -1: | |
raise FailedGrab() | |
string = string[:string.find(sub)] | |
return string | |
class BadCurrency(Exception): | |
pass | |
def get_currency(code): | |
code = code.upper() | |
page = urlopen("http://www.xe.com/symbols.php").read().decode("utf-8") | |
symbol = "" | |
try: | |
page = grab_end(page, "<td>" + code + "</td>") | |
page = grab_end(page, '<td class="cSmbl_Fnt_C2000">') | |
page = grab_start(page, "<") | |
except FailedGrab: | |
symbol = "?" | |
else: | |
symbol = html.unescape(page) | |
opener = build_opener() | |
opener.addheaders = [('User-Agent', 'Mozilla/5.0')] | |
response = opener.open("https://www.google.co.uk/finance/converter?a=1&from={0}&to=USD".format(code)) | |
page = response.read().decode("utf-8") | |
value = 0.0 | |
try: | |
page = grab_end(page, '= <span class=bld>') | |
page = grab_start(page, "<") | |
page = grab_start(page, " ") | |
except FailedGrab: | |
raise BadCurrency() | |
else: | |
value = float(page.strip()) | |
return Currency(code, symbol, value) | |
if __name__ == "__main__": | |
app = CurrencyConvertorApp() | |
app.main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment