#!/usr/bin/python # TYPE:sciencemath # DESC:Command line version of chemParse.py. _elements = open('elements.dat').read().strip() class Element: def __init__(self, symbol, name, mass): self.symbol, self.name, self.mass = symbol, name, mass def get_mass(self): return self.mass def add_amounts(self, amount, result): result[self.symbol] = result.get(self.symbol, 0) + amount class Formula: def __init__(self, *seq): self.seq = list(seq) self.count = 1 def append(self, newthing): self.seq.append(newthing) def get_mass(self): sum = 0.0 for thing in self.seq: sum = sum + thing.get_mass() return sum * self.count def set_count(self, newcount): self.count = newcount def add_amounts(self, amount, result): amount = amount * self.count for thing in self.seq: thing.add_amounts(amount, result) def show_amounts(self): result = {} self.add_amounts(1, result) items = result.items() items.sort() for sym, count in items: print "%d %s of %s (%s) atoms" % (count, add_s('mole', count), ELEMENTS[sym].name, sym) def show_atoms(self): result = {} self.add_amounts(1, result) items = result.items() items.sort() for sym, count in items: print "%s atoms of %s" % (str(count * NA), sym) def __len__(self): return len(self.seq) class Parser: def __init__(self, input): self.input = input + "" self.place = 0 def get_part(self): global ptype, pvalue self.lastplace = self.place m = _lexer(self.input, self.place) if m is None: print "Error in input" return 0 self.place = m.end() pvalue = m.group() if pvalue == '(': ptype = LPAR elif pvalue == ')': ptype = RPAR elif pvalue == '': ptype = EOS elif pvalue[0] in NUMBERS: ptype, pvalue = NUM, int(pvalue) else: ptype = NAME def add_s(string, count): if count != 1: return string+'s' else: return string def make_dict(orig): dict = {} for line in orig.split('\n'): if line.strip != '': symbol, name, mass = eval(line) dict[symbol] = Element(symbol, name, mass) return dict def parse(s): global pars, ptype, pvalue pars = Parser(s) pars.get_part() seq = parse_formula() return seq def parse_formula(): global pars, ptype, pvalue seq = Formula() while ptype in (LPAR, NAME): if ptype == LPAR: pars.get_part() newpart = parse_formula() if ptype != RPAR: print "Parenthesis failure" return 0 pars.get_part() else: if ELEMENTS.has_key(pvalue): newpart = Formula(ELEMENTS[pvalue]) else: print "Element not found!" return 0 pars.get_part() if ptype == NUM: newpart.set_count(pvalue) pars.get_part() seq.append(newpart) return seq ELEMENTS = make_dict(_elements) del _elements NA = 6.02e+23 NAME, NUM, LPAR, RPAR, EOS = range(5) NUMBERS = '0123456789' import re _lexer = re.compile("[A-Z][a-z]*|\d+|[()]|").match del re LINE = '-'*30 while __name__ == '__main__': x = raw_input("Formula? ") todo = raw_input("You want mass or moles? ") seq = parse(x) if seq and todo == 'mass': moles = input("Moles of substance? ") mass = seq.get_mass() * moles print LINE print "Molar mass: %d %s" % (mass, add_s('gram', mass) ) print LINE seq.show_amounts() seq.show_atoms() print "%s molecules" % (str(moles * NA)) print LINE elif seq and todo == 'moles': mass = input("Mass (in grams) of substance? ") moles = mass/seq.get_mass() print LINE print "There are %f %s of %s in %dg" % (moles, add_s('mole', moles), x, mass) print LINE seq.show_amounts() seq.show_atoms() print "%s molecules" % (str(moles * NA)) print LINE