/// <summary>Gets the chemical formula as a string in Hill notation.</summary> /// <param name="chemicalFormula">The chemical formula.</param> /// <returns></returns> public static string GetChemicalFormulaString(IChemicalFormula chemicalFormula) { // Local function for converting a single element to a string. string GetElementString(IEntityCardinality <IElement> element) { if (element.Count == 0) // Don't write zero. { return(string.Empty); } if (element.Count == 1) // If the count is 1, just use the symbol. { return(element.Entity.Symbol); } // In all other cases need to write out count too. return($"{element.Entity.Symbol}{element.Count}"); } // Main function. ICollection <IEntityCardinality <IElement> > elements = chemicalFormula.GetElements().ToList(); IList <string> elementStrings = new List <string>(); // Look for carbon first. If it exists, write it and then hydrogen. IEntityCardinality <IElement> carbon = elements.SingleOrDefault(e => e.Entity.AtomicNumber == 6); if (carbon != null && carbon.Count > 0) { elementStrings.Add(GetElementString(carbon)); elements.Remove(carbon); IEntityCardinality <IElement> hydrogen = elements.SingleOrDefault(e => e.Entity.AtomicNumber == 1); if (hydrogen != null && hydrogen.Count > 0) { elementStrings.Add(GetElementString(hydrogen)); elements.Remove(hydrogen); } } // Write out the rest in alphabetical order. foreach (IEntityCardinality <IElement> element in elements.OrderBy(e => e.Entity.Symbol)) { if (element.Count > 0) { elementStrings.Add(GetElementString(element)); } } return(string.Join("", elementStrings)); }
private IChemicalFormula SimpleParseTest(string formulaString, params Tuple <string, int>[] elements) { bool success = ChemicalFormula.TryParseString(formulaString, _elementProvider, out IChemicalFormula chemicalFormula); Assert.IsTrue(success); Assert.IsNotNull(chemicalFormula); IReadOnlyCollection <IEntityCardinality <IElement> > elementCollection = chemicalFormula.GetElements(); Assert.AreEqual(elements.Length, elementCollection.Count, "Element Count"); foreach (var(symbol, count) in elements) { IEntityCardinality <IElement> h = elementCollection.SingleOrDefault(e => e.Entity.Symbol == symbol); Assert.IsNotNull(h, $"For element '{symbol}{count}'"); Assert.AreEqual(count, h.Count, $"For element '{symbol}{count}'"); } return(chemicalFormula); }
private static bool HandleNewElement(ReadOnlySpan <char> formula, IElementProvider elementProvider, IDictionary <string, IEntityCardinality <IElement> > elementList, int symbolStart, int symbolEnd, int digitStart, int digitEnd, int isotopeStart, int isotopeEnd) { if (formula.Length == 0) { return(false); } // Handle cardinality int count = 1; if (digitStart != 0) { var digitSpan = formula.Slice(digitStart, digitEnd - digitStart + 1); if (!int.TryParse(digitSpan, out count)) { //throw new Exception($"Can't convert {digitSpan.ToString()} to an integer."); return(false); } if (count == 0) { return(true); // A valid cardinality, but nothing should be added to the formula } } // Handle isotopes int?isotope = null; if (isotopeStart != 0) { var isotopeSpan = formula.Slice(isotopeStart, isotopeEnd - isotopeStart + 1); int isotopeOut; if (!int.TryParse(isotopeSpan, out isotopeOut)) { //throw new Exception($"Can't convert {digitSpan.ToString()} to an integer."); return(false); } isotope = isotopeOut; } try { string symbol = formula.Slice(symbolStart, symbolEnd - symbolStart + 1).ToString(); var element = GetElement(symbol, isotope, count, elementProvider); if (elementList.ContainsKey(element.Entity.Symbol)) { IEntityCardinality <IElement> entityCardinality = elementList[element.Entity.Symbol]; elementList[symbol] = new EntityCardinality <IElement>(entityCardinality.Entity, entityCardinality.Count + count); } else { elementList.Add(element.Entity.Symbol, element); } return(true); } catch // Failed to get element for some reason { return(false); } }