Text Parsing

Knowing the problem, the solution can be found. First off, let's define some data for the elements

I'm doing this by first creating a string array for the elements and then a double array for the masses. I also have a List of type element which will be used to store the elements in (makes life simpler when doing comparisons - I did not use the list to store in initially for reasons which should become clear later)

public class element
{
  public string el;
  public double num;			
  public element(string e, double n)
  {
     this.el = e;
     this.num = n;
  }
}

List <element> elem = new List();
		
string[] elements = new string[] {"H","He",
  "Li","Be","B","C","N","O","F","Ne",
  "Na","Mg","Al","Si","P","S","Cl","Ar",
  "K","Ca","Sc","Ti","V","Cr","Mn","Fe","Co","Ni","Cu",
  "Zn","Ga","Ge","As","Se","Br","Kr",
  "Rb","Sr","Y","Zr","Nb","Mo","Tc","Ru","Rh","Pd","Ag",
  "Cd","In","Sn","Sb","Te","I","Xe",
  "Cs","Ba","La",
  "Ce","Pr","Nd","Pm","Sm","Eu","Gd","Tb","Dy","Ho","Er",
  "Tm","Yb","Lu",
  "Hf","Ta","W","Re","Os","Ir","Pt","Au","Hg","Tl","Pb",
  "Bi","Po","At","Rn",
  "Fr","Ra","Ac",
  "Th","Pa","U","Np","Pu","Am","Cm","Bk","Cf","Es","Fm",
  "Md","No","Lr",
  "Rf","Db","Sg","Bh","Hs","Mt", "Ds", "Rg"};
		
double [] atmass = new double[111] {1.0079,4.0026,
  6.941,9.01218,10.8,12.011,14.0067,15.9994,18.9984,20.179,
  22.9898,24.305,26.9815,28.0855,30.9738,32.06,35.453,39.948,
  39.0983,40.08,44.9559,47.88,50.9415,51.996,54.9380,55.847,
  58.9332,58.69,63.546,65.38,69.72,72.59,74.9216,78.96,79.904,83.8,
  85.4679,87.62,88.9059,91.22,92.9064,95.94,98,101.07,102.9055,
  106.42,107.868,112.41,114.82,118.69,121.75,127.6,126.9045,131.29,
  132.9054,137.33,138.9055,
  140.12,140.9077,144.24,145,150.36,151.96,157.25,158.9254,162.5,
  164.9304,167.26,168.9342,173.04,174.967,
  178.49,180.9479,183.85,186.207,190.2,192.22,195.08,196.9665,
  200.59,204.383,207.2,208.9804,209,210,222,
  223,226.0254,227.0278,
  232.0381,231.0359,238.0289,237.0482,244,243,247,247,251,252,
  257,258,259,260,
  261,262,263,264,265,266,267,268 };

 string [] numbers = new string[10] {"0","1","2","3",
                                     "4","5","6","7",
                                     "8","9"};

That's the elements and atomic weights all in. I've also added in another array which just stores numbers. These are to be used later on as well.

Test 1 - the text box

The first test that needs to be carried out is not on any sort of formula, but on the text entry box itself. There are a few tests that can be done here. The two simplest are to check if there is something actually in there and then if what's in there is valid (in other words, has the user entered an invalid element). These are two easy tasks. Other checks are also performed (for example missing braces)

void calculate(object sender, EventArgs e)
{
   if (formula.Text.Length == 0)
   {
      MessageBox.Show("Error : You haven't entered a formula",
                      "Formula error", 
                      MessageBoxButtons.OK,MessageBoxIcon.Error);
      return;
   }

The simplest of errors - if the calculate button has been pressed, nothing can happen if there is nothing to work with

   if ((formula.Text.Contains("(") && !formula.Text.Contains(")"))||
        (formula.Text.Contains(")") && !formula.Text.Contains("(")))
   {
      MessageBox.Show("Error : You have a missing brace within your 
                       formula. Please recheck", 
                      "Bracket error", MessageBoxButtons.OK,
                      MessageBoxIcon.Error);
      return;
   }

A quick check to ensure that the braces match up. This only checks to make sure there is a ( and a ), but not the number of them. It would be quite trivial to add in a number of braces check.

   if (formula.Text.Length == 1)
   {
      bool test = true;	
      foreach (string element in elements)
      {
         if (formula.Text.Contains(element))
         {
            test = false;
	         continue;
         }
      }
      if (test == true)
      {
         MessageBox.Show("Error : Your formula contains an 
                         unknown element", 
                         "Unknown element", MessageBoxButtons.OK,
                         MessageBoxIcon.Error);
         return;
      }
    }

Let's make sure that the elements entered in the formula actually exist shall we...

    if (formula.Text.Contains("."))
    {
       int pos = formula.Text.IndexOf(".");
       if (pos == formula.Text.Length)
       {
          MessageBox.Show("Error : You have a period followed by 
                          nothing", 
                          "Period error", MessageBoxButtons.OK,
                          MessageBoxIcon.Error);
          return;
       }
     }

Okay, we have a dot in the formula. Let's do a quick sanity check - is there anything after it?

	
     string dupeform = formula.Text;

     if (dupeform.Contains("("))
        dupeform = dupeform.Remove(dupeform.IndexOf("("), 1);
     if (dupeform.Contains(")"))
        dupeform = dupeform.Remove(dupeform.IndexOf(")"), 1);
     if (dupeform.Contains("."))
        dupeform = dupeform.Remove(dupeform.IndexOf("."), 1);
     for (int a = 0; a < dupeform.Length; ++a)
     {
        foreach (string n in numbers)
        {
          if (dupeform.Contains(n))
             dupeform = dupeform.Remove(dupeform.IndexOf(n), 1);
        }
     }

This part may strike as being a bit odd. I've made a duplicate copy of the validated text and have then removed all of the numbers, braces and periods - it's just a sanity check. It's now clear why I've created a string containing numbers

			
   dupeform = formula.Text + "#";
   search(dupeform, false);
   results();
}

The duplicate is then passed to the search routine and the results method called

The search routine