Skip to content

Instantly share code, notes, and snippets.

@fourohfour
Last active November 6, 2016 06:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fourohfour/f0d9660081525640b1249f5f104f02e6 to your computer and use it in GitHub Desktop.
Save fourohfour/f0d9660081525640b1249f5f104f02e6 to your computer and use it in GitHub Desktop.
Currency Convertor
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