The function parseMolecule counts the number of atoms of each element contained in the molecule, in a given chemical formula represented by a string, and returns an object.
Sample output for formula H2O: {H: 2, O: 1}
A script by V.
| parseMolecule = (formula) -> | |
| # console.log 'formula ' + formula | |
| elements = {} | |
| countElements = (input) -> | |
| # console.log 'count elements ' + input | |
| elts = input.match /[A-Z]([a-z])?(\d+)?/g | |
| for i in [0..elts.length - 1] by 1 | |
| elt = (elts[i].match /[A-Z]([a-z])?(?=\d+)?/)[0] | |
| count = elts[i].match /\d+/ | |
| count = if not count then 1 else (count.map (item) -> parseInt(item))[0] | |
| elements[elt] = if elements[elt] >= 0 then elements[elt] + count else count | |
| openBrackets = (input, closingBracket) -> | |
| # console.log 'open brackets, input ' + input | |
| output = '' | |
| multiplier = if (input.split closingBracket)[1] is '' then 1 else parseInt((input.split closingBracket)[1]) | |
| # console.log multiplier | |
| elts = input.match /[A-Z]([a-z])?(\d+)?/g | |
| for i in [0..elts.length - 1] by 1 | |
| elt = elts[i] | |
| eltName = (elt.match /^[A-Z]([a-z])?/)[0] | |
| atoms = if elt.match /\d+$/ then parseInt((elt.match /\d+$/)[0]) else 1 | |
| atoms *= multiplier | |
| output += eltName + atoms | |
| # console.log 'output ' + output | |
| formula = formula.replace input, output | |
| return output | |
| if /(\[|\]|\{|\}|\(|\))/.test formula | |
| # console.log 'extract inner round brackets first' | |
| formulaDecomp = formula.match /\([^\(\)]+\)\d*/g | |
| if formulaDecomp | |
| # console.log 'extract round, formulaDecomp ' + formulaDecomp | |
| for i in [0..formulaDecomp.length - 1] by 1 | |
| item = formulaDecomp[i] | |
| openBrackets item, ')' | |
| # console.log 'extract middle square brackets' | |
| formulaDecomp = formula.match /\[[^\[\]]+\]\d*/g | |
| if formulaDecomp | |
| # console.log 'extract square, formulaDecomp ' + formulaDecomp | |
| for i in [0..formulaDecomp.length - 1] by 1 | |
| item = formulaDecomp[i] | |
| openBrackets item, ']' | |
| # console.log 'extract outer curly brackets' | |
| formulaDecomp = formula.match /\{[^\[\]]+\}\d*/g | |
| if formulaDecomp | |
| # console.log 'extract curly, formulaDecomp ' + formulaDecomp | |
| for i in [0..formulaDecomp.length - 1] by 1 | |
| item = formulaDecomp[i] | |
| openBrackets item, '}' | |
| if not /(\[|\]|\{|\}|\(|\))/.test formula | |
| # console.log 'no brackets' | |
| countElements formula | |
| # console.log 'elements ' + elements | |
| return elements | |
| # TEST | |
| parseMolecule 'H2O' # {H: 2, O: 1}) | |
| parseMolecule 'Mg(OH)2' # {Mg: 1, O: 2, H: 2}) | |
| parseMolecule 'K4[ON(SO3)2]2' # {K: 4, O: 14, N: 2, S: 4}) | |
| parseMolecule 'As2{Be4C5[BCo3(CO2)3]2}4Cu5' # {As: 2, B: 8, Be: 16, C: 44, Cu: 5, Co: 24, O: 48} |
| function parseMolecule(formula) { | |
| // console.log('formula:', formula); | |
| let elements = {}; | |
| function countElements(input) { | |
| // console.log('count elements, input:', input); | |
| const elts = input.match(/[A-Z]([a-z])?(\d+)?/g); | |
| for (let i in elts) { | |
| const elt = elts[i].match(/[A-Z]([a-z])?(?=\d+)?/)[0]; | |
| let count = elts[i].match(/\d+/); | |
| count = (!count) ? 1 : count.map(Number)[0]; | |
| // console.log(elt, '|', count); | |
| if (elements.hasOwnProperty(elt)) { elements[elt] += count; } | |
| else { elements[elt] = count; } | |
| } | |
| // console.log('elements:', elements); | |
| } | |
| function openBrackets(input, closingBracket = ')') { | |
| let output = ''; | |
| const multiplier = parseInt(input.split(closingBracket)[1]) || 1; | |
| const elts = input.match(/[A-Z]([a-z])?(\d+)?/g); | |
| // console.log('elts: ',elts); | |
| for (let elt of elts) { | |
| const eltName = elt.match(/^[A-Z]([a-z])?/)[0]; | |
| // console.log('eltName:', eltName); | |
| let atoms = (elt.match(/\d+$/)) ? parseInt(elt.match(/\d+$/)[0]) : 1; | |
| // console.log('init atoms:', atoms); | |
| atoms *= multiplier; | |
| // console.log('resulting atoms:', atoms); | |
| output += eltName + atoms; | |
| } | |
| // console.log(output); | |
| formula = formula.replace(input, output); | |
| return output; | |
| }; | |
| if (/(\[|\]|\{|\}|\(|\))/.test(formula)) { | |
| // console.log('brackets detected, extract elements from brackets:', formula); | |
| // extract inner round brackets first | |
| let formulaDecomp = formula.match(new RegExp(/\([^\(\)]+\)\d*/, 'g')); | |
| // console.log('formulaDecomp, round brackets:', formulaDecomp); | |
| if (formulaDecomp) { | |
| for (let item of formulaDecomp) { | |
| //console.log('item:', item); | |
| openBrackets(item, ')'); | |
| // console.log(' >> formula:', formula); | |
| } | |
| } | |
| // extract middle square brackets | |
| formulaDecomp = formula.match(new RegExp(/\[[^\[\]]+\]\d*/, 'g')); | |
| // console.log('formulaDecomp, square brackets:', formulaDecomp); | |
| if (formulaDecomp) { | |
| for (let item of formulaDecomp) { | |
| openBrackets(item, ']'); | |
| // console.log(' >> formula:', formula); | |
| } | |
| } | |
| // extract outer curly brackets | |
| formulaDecomp = formula.match(new RegExp(/\{[^\[\]]+\}\d*/, 'g')); | |
| // console.log('formulaDecomp, curly brackets:', formulaDecomp); | |
| if (formulaDecomp) { | |
| for (let item of formulaDecomp) { | |
| openBrackets(item, '}'); | |
| // console.log(' >> formula:', formula); | |
| } | |
| } | |
| } | |
| if (!/(\[|\]|\{|\}|\(|\))/.test(formula)) { | |
| // console.log('no brackets, count elements:', formula); | |
| countElements(formula); | |
| } | |
| return elements; | |
| } | |
| // TEST | |
| parseMolecule('H2O'); // {H: 2, O: 1}) | |
| parseMolecule('Mg(OH)2'); // {Mg: 1, O: 2, H: 2}) | |
| parseMolecule('K4[ON(SO3)2]2'); // {K: 4, O: 14, N: 2, S: 4}) | |
| parseMolecule('As2{Be4C5[BCo3(CO2)3]2}4Cu5'); // {As: 2, B: 8, Be: 16, C: 44, Cu: 5, Co: 24, O: 48} |