Skip to content

Instantly share code, notes, and snippets.

@Astarta0
Last active July 15, 2018 18:06
Show Gist options
  • Save Astarta0/843c765482bbb38d740f15e6b9c97707 to your computer and use it in GitHub Desktop.
Save Astarta0/843c765482bbb38d740f15e6b9c97707 to your computer and use it in GitHub Desktop.
const isDebug = false;
const bracketsOpenRegexp = /[\[\{]/g;
const bracketsCloseRegexp = /[\]\}]/g;
const digitRegExp = /^\d+$/;
const coefregExp = /^\d+/;
const log = (...args) => isDebug ? console.log(...args) : null;
function parseMolecule(formula, coefficient = 1) {
let molecule = {};
log('1 - formula ', formula);
if (!formula) {
return molecule;
}
// если формула не массив (строка)
if(!Array.isArray(formula)) {
// приводим все скобки к одному типу
formula = transformBrackets(formula);
log('2 - transformBrackets ', formula);
// парсим строку в структуру
formula = parseBrackects(formula);
log('3 - parseBrackects ', formula);
}
// это простая формула - без скобок
if(isSimpleFormula(formula)) {
formula = formula.join('');
molecule = transformSimpleFormulaToObject(formula);
molecule = multiply(molecule, coefficient);
return molecule;
}
// отделяем коэффициенты, если они есть
formula = splitCoefficients(formula);
log('4 - splitCoefficients ', formula);
formula.forEach((value, index, array) => {
if(Array.isArray(value)) {
let coef = 1;
let nextValue = array[index+1];
// следующий элемент - коэффициент?
if (nextValue && digitRegExp.test(nextValue)) {
// если это коэффициент
coef = nextValue;
}
molecule = merge(molecule, parseMolecule(value, coef));
} else if (!digitRegExp.test(value)) {
//часть простой формулы и не число
molecule = merge(molecule, transformSimpleFormulaToObject(value));
}
});
molecule = multiply(molecule, coefficient);
return molecule;
}
const transformSimpleFormulaToObject = formula => {
const elementRegexp = /([A-Z][a-z]*)\d*/g;
let arrOfElements = formula.match(elementRegexp);
const reg = /(?=\d+)/i;
const molecule = {};
arrOfElements.forEach(value => {
let [name, ...count] = value.split(reg);
count = +count.join('') || 1;
if (molecule[name]) {
molecule[name] = molecule[name] + count;
return;
}
molecule[name] = count;
});
return molecule;
};
const isSimpleFormula = (formula) => {
return formula.every(value => !Array.isArray(value));
};
const merge = (molecule, leftoverMolecule) => {
let setKeys = new Set([...Object.keys(molecule), ...Object.keys(leftoverMolecule)]);
let res = {};
for (let key of setKeys) {
if (molecule[key] && leftoverMolecule[key]) {
res[key] = molecule[key] + leftoverMolecule[key];
} else if (molecule[key]) {
res[key] = molecule[key];
}
else if (leftoverMolecule[key]) {
res[key] = leftoverMolecule[key];
}
}
return res;
};
const multiply = (molecule, coefficient = 1) => {
for (const elementName in molecule) {
molecule[elementName] = molecule[elementName] * coefficient;
}
return molecule;
};
const parseBrackects = (formula) => {
const t = formula.replace(/\(/g, '",["').replace(/\)/g, '"],"');
return JSON.parse(`["${t}"]`).filter(item=> item!=='');
};
const transformBrackets = (formula) => {
return formula.replace(bracketsOpenRegexp, '(').replace(bracketsCloseRegexp, ')');
};
const splitCoefficients = (partsOfFormula) => {
let resArr = [];
for(let i=0; i< partsOfFormula.length; i++) {
//если элемент - массив
if (Array.isArray(partsOfFormula[i])) {
resArr.push(splitCoefficients(partsOfFormula[i]));
} else {
//если элемент - строка
const coef = partsOfFormula[i].match(coefregExp);
if(coef) {
const partWithoutCoef = partsOfFormula[i].replace(coefregExp, '');
resArr.push(coef[0]);
if (partWithoutCoef) {
resArr.push(partWithoutCoef);
}
} else {
resArr.push(partsOfFormula[i]);
}
}
}
return resArr.filter(item=> item!=='');
};
// Tests
// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
console.assert(equalsAtomically(parseMolecule("H2O"), { H: 2, O: 1 }));
console.assert(equalsAtomically(parseMolecule("H2SO3"), { H: 2, S: 1, O: 3 }));
console.assert(equalsAtomically(parseMolecule("C6H12O6"), { C: 6, H: 12, O: 6 }));
console.assert(equalsAtomically(parseMolecule("Mg(OH)2"), {Mg: 1, O: 2, H: 2}));
console.assert(equalsAtomically(parseMolecule("K4[ON(SO3)2]2"), {K: 4, O: 14, N: 2, S: 4}));
console.assert(equalsAtomically(parseMolecule("(C5H5)Fe(CO)2CH3"), { C: 8, H: 8, Fe: 1, O: 2}));
console.assert(equalsAtomically(parseMolecule("C2H2(COOH)2"), { C: 4, H: 4, O: 4 }));
function equalsAtomically(obj1, obj2) {
if (Object.keys(obj1).length == Object.keys(obj2).length) {
for (var k in obj1) {
if (obj1[k] != obj2[k]) return false;
}
return true;
}
return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment