/// <summary> /// Parses a chemical formula expressed as "[{atom}[count][spaces]]*", /// e.g. "C6H11ON", where supported atoms are H, O, N, C, S or P, etc. /// returning the total mass for the formula. /// /// The parser removes atoms and counts until it encounters a character /// it does not understand as being part of the chemical formula. /// The remainder is returned in the desc parameter. /// /// This parser will stop at the first minus sign. If you need to parse /// an expression that might contain a minus sign, use <see cref="ParseMassExpression"/>. /// </summary> /// <param name="desc">Input description, and remaining string after parsing</param> /// <returns>Total mass of formula parsed</returns> public double ParseMass(ref string desc) { double totalMass = 0.0; desc = desc.Trim(); Molecule mol; Adduct adduct; string neutralFormula; if (IonInfo.IsFormulaWithAdduct(desc, out mol, out adduct, out neutralFormula)) { totalMass += mol.Sum(p => p.Value * GetMass(p.Key)); desc = string.Empty; // Signal that we parsed the whole thing return(totalMass); } while (desc.Length > 0) { string sym = NextSymbol(desc); double massAtom = GetMass(sym); // Stop if unrecognized atom found. if (massAtom == 0) { // CONSIDER: Throw with a useful message? break; } desc = desc.Substring(sym.Length); int endCount = 0; while (endCount < desc.Length && Char.IsDigit(desc[endCount])) { endCount++; } long count = 1; if (endCount > 0) { if (!long.TryParse(desc.Substring(0, endCount), out count)) { count = long.MaxValue; // We know at this point that it should parse, so it's probably just too big } } totalMass += massAtom * count; desc = desc.Substring(endCount).TrimStart(); } return(totalMass); }
/// <summary> /// Parses a chemical formula expressed as "[{atom}[count][spaces]]*", /// e.g. "C6H11ON", where supported atoms are H, O, N, C, S or P, etc. /// returning the total mass for the formula. /// /// The parser removes atoms and counts until it encounters a character /// it does not understand as being part of the chemical formula. /// The remainder is returned in the desc parameter. /// /// This parser will stop at the first minus sign. If you need to parse /// an expression that might contain a minus sign, use <see cref="ParseMassExpression"/>. /// </summary> /// <param name="desc">Input description, and remaining string after parsing</param> /// <param name="molReturn">Optional dictionary for returning the atoms and counts</param> /// <returns>Total mass of formula parsed</returns> public double ParseMass(ref string desc, Dictionary <string, int> molReturn = null) { double totalMass = 0.0; desc = desc.Trim(); Molecule mol; Adduct adduct; string neutralFormula; Dictionary <string, int> dict = null; if (IonInfo.IsFormulaWithAdduct(desc, out mol, out adduct, out neutralFormula)) { totalMass += mol.Sum(p => p.Value * GetMass(p.Key)); desc = string.Empty; // Signal that we parsed the whole thing if (molReturn != null) { dict = mol.Dictionary.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); } } else { if (molReturn != null) { dict = new Dictionary <string, int>(); } while (desc.Length > 0) { string sym = NextSymbol(desc); double massAtom = GetMass(sym); // Stop if unrecognized atom found. if (massAtom == 0) { // CONSIDER: Throw with a useful message? break; } desc = desc.Substring(sym.Length); int endCount = 0; while (endCount < desc.Length && Char.IsDigit(desc[endCount])) { endCount++; } var count = 1; if (endCount > 0) { if (!int.TryParse(desc.Substring(0, endCount), out count)) { count = int.MaxValue; // We know at this point that it should parse, so it's probably just too big } } totalMass += massAtom * count; if (dict != null) { if (dict.TryGetValue(sym, out var oldCount)) { dict[sym] = count + oldCount; } else { dict.Add(sym, count); } } desc = desc.Substring(endCount).TrimStart(); } } if (molReturn != null) { foreach (var kvp in dict) { var sym = kvp.Key; var count = kvp.Value; if (molReturn.TryGetValue(sym, out var oldCount)) { molReturn[sym] = count + oldCount; } else { molReturn.Add(sym, count); } } } return(totalMass); }