Reading in one character at a time

Hi!

We have to find out that in chemical formulas how can we read and the use of binary search for searching particular elements and get correct atomic weight by multiplying them. Please help me out, I want to learn as soon as possible for my finals.

Instructions:

Department of Chemistry has assigned you a task to design a program that will find out molecular weights of compounds by calculating. For example weight of 2 hydrogen atoms 1.008 and of 1 oxygen 15.999 in H2O, so the water contains the following weight 2 x 1.008 + 1 x 15.999 yielding 18.015 atomic weight.
The form of input to your program will be like this:

element ( number of atoms it has) element (number of atoms it contains)
For example H2O would be written as H(2)O, in case the ()'s are not available, suppose one (1) atom. Another example of acetic acid would be written as CH(3)COOH or could be C(2)H(4)O(2).

If an element contains two letters symbol, the first letter will be in upper case and the second letter in lower case Silver is Ag .
In 'Element.dat’ data file we can have the record of all chemical elements. This record will have per line one input element the elements names are shown by their atomic weights.

Ex. Al 26.98
Sb 121.75
S 32.06
Ba 137.34

'Formula.dat' second input file possess test formulae per line with one formula that can be used to check out your program.
Restrictions: To carry the Symbol and its weight there you need an array structure.

In the element table apply Binary search to develop elements.
For implementation you need Functions/Procedures.
In a table form arrange your output using headings and straight columns.

formula text file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Na(3)P(5)O(4)
TeCl(4)
V(2)O(5)
HCONHCH(2)CH(2)OH
ZnC(4)H(6)O(4)
UO(2)N(2)O(6)H(2)O
FeTiO(3)
MgC(4)H(6)O(4)
C(16)N(33)OH
AgSiF(6)MgOH(6)O(3)
NiSO(4)N(2)H(4)SO(4)H(12)O(6)
Tl(2)S(3)O(12)H(14)O(7)
CBr(4)
ZnCO(3)
UO(2)CO(3)
ThS(2)O(8)
H(4)P(2)O(5)
H(2)SeO(5)
K(2)Cr(2)O(7)
K(2)PtI(6)

Element.txt file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
H 1.008
C 12.011
N 14.0067
O 15.9994
F 18.9984
Na 22.9898
Mg 24.305
Al 26.9815
Si 28.086
P 30.9738
S 32.06
Cl 35.453
K 39.102
Ti 47.9
V 50.9414
Cr 51.996
Fe 55.847
Ni 58.71
Zn 65.37
As 74.9216
Se 78.96
Br 79.904
Ag 107.868
I 126.905
Te 127.6
Pt 195.09
Au 196.967
Tl 204.37
Th 232.038
U 238.029
> Please help me out, I want to learn as soon as possible for my finals.
You'd learn a lot more if you made an attempt first.

Showing how much you know and where you get stuck means you get specific targeted responses to your query.

Looking a someone else's spoon-fed answer isn't going to teach you much.
What have you attempted? What is your C++ issue? if you post what you're done so far then we can advise on that and suggest ways forward.

Can you read the Element.txt file into a suitable structure? Can you read a single formula and parse it into its parts?

This kind of string parsing is obnoxious, and a whole lot of CS literature is dedicated to it. I don't think it is well-taught in universities either; professors tend to ask people to figure it out.

Remember, user input and parsing is not easy.


Break It Down

Each formula is a string of atoms. Each atom has the form:

  name count?

The name is a single majuscule, optionally followed by a single minuscule.
The count is optional. If present, it is a list of digits bracketed by parentheses:

  '(' digits ')'

If not present, the count is taken to have value = 1.


Accept / Expect Idiom

There is a basic parsing algorithm wherein you behave depending on the next character in the input.

  • accept --> get the next character IFF it is what is desired
                    (and report whether it was accepted)

  • expect --> the next character MUST be what is desired
                    (failure if it is not)

Your code should look to see if it can accept the next character in a string for each part of the atom. Your parsing routine should therefore look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  // pseudocode

  function get_next_atom( string, index, &name, &count ):

    name = expect an uppercase letter
    if (accept a lowercase letter):
      name += that lowercase letter

    if (accept an open parenthesis):
      expect a digit
      accept more digits
      count = string to integer( all digits )
      expect a close parenthesis

    else:
      count = 1

That is very high-level pseudocode.
Your assignment (at this level) does not say it explicitly, but you can presume that the input is well-formed. A lot of the expect --> error stuff can be ignored. (The only one NOT to ignore would be the first because you have hit the end of the string == no more atoms.)

You can translate that into C++ code fairly simply:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
bool get_next_atom( string s, unsigned n, string& name, unsigned& count )
{
  // expect an uppercase letter
  if ((n >= s.size()) or (!isupper( s[n] )) return false;
  n += 1;

  // if (accept a lowercase letter):
  if (islower( s[n] ))
  {
    // name += that lowercase letter
    name += s[n];
    n += 1;
  }

  ...
}

It does look kind of messy, but you are spelling out exactly what to expect or accept at each step and how to behave on success or failure. There isn't much you can do to clean it up prettier.

Hope this helps.
Last edited on
First: learn how to read a line from a text file into a string variable.
Last edited on
@forgottencoder, et al.
I dislike assuming the lowest common opinion on questions.
I admit it does look like OP is just asking for a handout... but OP is not the only person in his class that will find this post, and just reading "don' be stoopid" doesn't help anyone.

I chose (in this case, at least) to think that OP (and/or classmates) is really just having a hard time with the hardest part: parsing those formulas.

This assignment has the following pedagogical properties:
  • manipulating arrays
  • arrays as data structures
  • binary search
  • insertion sort
  • basic text parsing (recognizing element boundaries)

Personally, I think that the hardest part of this whole thing is the stupid text parsing.
—At least, that has been my experience with students of any programming language.

Of course, I could just be wasting my time here...
This might be a practical start. The next 'trick is to put the individual characters back to a string of 2 characters and keep track of integers, then on to the binary search. Keep in mind the absence of a pair of brackets means an integer value of 1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <iostream>
#include <string>
#include <iomanip>

#include <fstream>

std::ifstream openFile(std::string &name)
{
    std::ifstream stm;
    stm.open(name);
    
    if(!stm)
    {
        std::cout << "Error\n";
    }
    
    return stm;
}


int main()
{
    std::string file_name{"formula.txt"};
    std::ifstream inputFile = openFile(file_name);
    
    std::string line;
    char temp;
    
    
    while( std::getline(inputFile, line) )
    {
        std::cout << std::setw(35) << std::right << line << " : ";
        
        for(int i = 0; i < line.length(); i++)
        {
            temp = line[i];
            if( std::isalpha(temp) )
            {
                if( std::isupper(temp) )
                    std::cout << ' ';
                
                std::cout << temp;
            }
            
            if( std::isdigit(temp) )
                std::cout << ' ' << temp;
        }
        
        std::cout << '\n';
        
    }
    
    inputFile.close();
    return 0;
}


                      Na(3)P(5)O(4) :  Na 3 P 5 O 4
                            TeCl(4) :  Te Cl 4
                           V(2)O(5) :  V 2 O 5
                  HCONHCH(2)CH(2)OH :  H C O N H C H 2 C H 2 O H
                     ZnC(4)H(6)O(4) :  Zn C 4 H 6 O 4
                 UO(2)N(2)O(6)H(2)O :  U O 2 N 2 O 6 H 2 O
                           FeTiO(3) :  Fe Ti O 3
                     MgC(4)H(6)O(4) :  Mg C 4 H 6 O 4
                       C(16)N(33)OH :  C 1 6 N 3 3 O H
                AgSiF(6)MgOH(6)O(3) :  Ag Si F 6 Mg O H 6 O 3
      NiSO(4)N(2)H(4)SO(4)H(12)O(6) :  Ni S O 4 N 2 H 4 S O 4 H 1 2 O 6
            Tl(2)S(3)O(12)H(14)O(7) :  Tl 2 S 3 O 1 2 H 1 4 O 7
                             CBr(4) :  C Br 4
                            ZnCO(3) :  Zn C O 3
                         UO(2)CO(3) :  U O 2 C O 3
                         ThS(2)O(8) :  Th S 2 O 8
                       H(4)P(2)O(5) :  H 4 P 2 O 5
                         H(2)SeO(5) :  H 2 Se O 5
                      K(2)Cr(2)O(7) :  K 2 Cr 2 O 7
                         K(2)PtI(6) :  K 2 Pt I 6
Program ended with exit code: 0
One thing to notice is there isn't a whole lot of difference between your elemental table and your formula:

1
2
3
4
5
6
7
8
9
10
11
struct Element
{
  std::string name;
  double      weight;
};

struct Atom
{
  std::string name;
  unsigned    count;
};

You could totally reuse the structure. A double easily handles anything an unsigned integer can. That's what I did:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct Element
{
  std::string name;    // abbreviated element name
  union
  {
    double    weight;  // provided by the list of elements
    unsigned  count;   // provided as part of the molecular formula
  };
};


// There are 118 recognized atomic elements.

// Fun fact: There is no size limit on molecules. Polymers, in particular, make
// some pretty large molecules, like individual tires and wind turbine blades.
// https://www.quora.com/Whats-the-biggest-known-molecule

using Elements = Element[ 118 ];

Then, later in main(), you can use the same structure however you need it. The only difference is how you populate it. In the first case, you load from your "element.txt" file.
In the second you parse a line from your "formulas.dat" file into a single element.

1
2
3
4
5
6
7
8
9
10
11
int main()
{
  Elements elements;
  unsigned num_elements = load_element_list_from_file( elements, "element.txt" );

  std::ifstream f( "formulas.dat" );
  std::string s;
  while (getline( f, s ) and !s.empty())
  {
    Elements formula;
    unsigned formula_size = parse_formula_from_string( formula, s );
As a simple starter with some error parse detection, perhaps consider (as C++17):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <string>
#include <iostream>
#include <iomanip>
#include <vector>
#include <fstream>
#include <map>
#include <cstdlib>

struct Chem {
	std::string name;
	unsigned atom {};
};

using Elems = std::map<std::string, double>;
using Mols = std::vector<Chem>;

Elems readElem() {
	std::ifstream felem("element.txt");
	Elems elems;

	if (!felem)
		std::cout << "Cannot open element file\n";
	else {
		std::string enam;
		double wgt {};

		while (felem >> enam >> wgt)
			elems[enam] = wgt;
	}

	return elems;
}

Mols parse(const std::string& chem) {
	Mols mol;

	for (auto cur {chem.begin()}; cur != chem.end(); ) {
		char elem[3] {};
		int atom {1};

		if (std::isupper(*cur)) {
			elem[0] = *cur++;

			if (cur != chem.end()) {
				if (std::islower(*cur))
					elem[1] = *cur++;

				if (cur != chem.end() && *cur == '(') {
					char* endp {};

					atom = strtol(&*++cur, &endp, 10);
					if (*endp == ')')
						cur += endp - &*cur + 1;
					else {
						std::cout << "')' expected\n";
						break;
					}
				}
			}
		} else {
			std::cout << "Upper case expected\n";
			break;
		}

		mol.emplace_back(elem, atom);
	}

	return mol;
}

void display(const Mols& mol, const Elems& elems, const std::string& chem)
{
	double wghts {};

	for (const auto& [nam, atom] : mol)
		if (const auto itr {elems.find(nam)}; itr != elems.end())
			wghts += atom * itr->second;
		else
			std::cout << nam << " not found\n";

	std::cout << std::left << std::setw(30) << chem << "  " << std::fixed << std::right << std::setw(9) << std::setprecision(4) << wghts << '\n';
}

int main() {
	const auto elems {readElem()};

	if (elems.empty())
		return 1;

	std::ifstream form("formula.txt");

	if (!form)
		return (std::cout << "Cannot open formula file\n"), 2;

	for (std::string chem; std::getline(form, chem); display(parse(chem), elems, chem));
}



Na(3)P(5)O(4)                    287.8360
TeCl(4)                          269.4120
V(2)O(5)                         181.8798
HCONHCH(2)CH(2)OH                 89.0945
ZnC(4)H(6)O(4)                   183.4596
UO(2)N(2)O(6)H(2)O               412.0530
FeTiO(3)                         151.7452
MgC(4)H(6)O(4)                   142.3946
C(16)N(33)OH                     671.4045
AgSiF(6)MgOH(6)O(3)              344.2950
NiSO(4)N(2)H(4)SO(4)H(12)O(6)    390.9630
Tl(2)S(3)O(12)H(14)O(7)          823.0206
CBr(4)                           331.6270
ZnCO(3)                          125.3792
UO(2)CO(3)                       330.0370
ThS(2)O(8)                       424.1532
H(4)P(2)O(5)                     145.9766
H(2)SeO(5)                       160.9730
K(2)Cr(2)O(7)                    294.1918
K(2)PtI(6)                      1034.7240

Last edited on
@seeplus, your answer is very similar to the C++ solution I wrote for myself. Useless for the OP, of course, since all that fancy C++ stuff is out (excepting strings and file streams).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <cctype>
#include <ciso646>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <regex>
#include <string>
#include <unordered_map>
#include <vector>


using Name   = std::string;
using Weight = double;
using Count  = unsigned;


//-------------------------------------------------------------------------------------------------
// This is our element lookup table

using Elements = std::unordered_map <Name, Weight> ;

std::istream& operator >> ( std::istream& ins, Elements& elements )
{
  Name   name;
  Weight weight;
  while (ins >> name >> weight)        // While there are a name and weight...
    elements.emplace( name, weight );  // ... add them to our lookup table
  return ins;
}


//-------------------------------------------------------------------------------------------------
// This is a formula

struct Atom
{
  Name  name;
  Count count;
};

using Formula = std::vector <Atom> ;

Formula& operator >> ( const std::string& s, Formula& formula )
{
  formula.clear();

  // Regular expression matching does all the parsing stuff for us
  std::regex re( "([A-Z][a-z]?)(\\(([0-9]+)\\))?" );
  //               -----1-----      ---3--
  //                 F    e     '('  73...  ')'

  auto begin = std::sregex_iterator( s.begin(), s.end(), re );
  auto end   = std::sregex_iterator();

  for (auto matches = begin;  matches != end;  ++matches)
  {
    auto  name  = (*matches)[1];
    auto  count = matches->length( 3 ) ? std::stoul( (*matches)[3] ) : 1;
    formula.emplace_back( Atom{ name, count } );
  }

  return formula;
}


//-------------------------------------------------------------------------------------------------

template <typename T> T& lvalue( T&& arg ) { return arg; }

int main()
{
  Elements elements;
  lvalue( std::ifstream( "element.txt" ) ) >> elements;

  std::cout << std::setw( 12 ) << std::right << "-----WEIGHT" << "  FORMULA------------\n";
  std::cout << std::fixed << std::setprecision( 4 );

  std::ifstream f( "formulas.dat" );
  std::string s;
  while (getline( f, s ) and !s.empty())
  {
    Formula formula;
    s >> formula;

    Weight weight = 0.0;
    for (auto atom : formula)
    {
      weight += elements[atom.name] * atom.count;
    }

    std::cout << std::setw( 12 ) << weight << "  " << s << "\n";
  }
}
 -----WEIGHT  FORMULA------------
    287.8360  Na(3)P(5)O(4)
    269.4120  TeCl(4)
    181.8798  V(2)O(5)
     89.0945  HCONHCH(2)CH(2)OH
    183.4596  ZnC(4)H(6)O(4)
    412.0530  UO(2)N(2)O(6)H(2)O
    151.7452  FeTiO(3)
    142.3946  MgC(4)H(6)O(4)
    671.4045  C(16)N(33)OH
    344.2950  AgSiF(6)MgOH(6)O(3)
    390.9630  NiSO(4)N(2)H(4)SO(4)H(12)O(6) 
    823.0206  Tl(2)S(3)O(12)H(14)O(7)
    331.6270  CBr(4)
    125.3792  ZnCO(3)
    330.0370  UO(2)CO(3)
    424.1532  ThS(2)O(8)
    145.9766  H(4)P(2)O(5)
    160.9730  H(2)SeO(5)
    294.1918  K(2)Cr(2)O(7)
   1034.7240  K(2)PtI(6)

I tended to be a little more wordy than you, even though my LLOC is slightly under yours... (weird how that works).

My code tends toward simply ignoring all errors, so if the user isn’t paying attention he may not notice that an answer is incorrect.

This was the second solution I wrote. I first wrote one that complied with the assignment’s requirements: no vectors or maps or anything nice like that.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <map>

std::ifstream openFile(std::string &name)
{
    std::ifstream stm;
    stm.open(name);
    
    if( !stm ) { std::cout << "Error\n";  }
    
    return stm;
}

int main()
{
    // MAP THE ELEMENT WEIGHTS
    std::string element_file{"element.txt"};
    std::ifstream element = openFile(element_file);
    std::map<std::string, double> element_map;
    std::string key;
    double value;
    while( element >> key >> value){ element_map.insert({key,value});}
    element.close();
    
    // NORMALIZE FORMULAE
    std::string formulae_file{"chemistry_formula.txt"};
    std::ifstream formulae = openFile(formulae_file);
    std::string line;
    char tmp;
    while( std::getline(formulae, line) )
    {
        std::cout << std::setw(35) << std::right << line << " : ";
        for(int i = 0; i < line.length(); i++)
        {
            tmp = line[i];
            if( tmp == '(' or tmp == ')') { line[i] = ' ';}
            if( ( isupper(tmp) and isupper(line[i+1]) )
               or ( islower(tmp) and isupper(line[i+1]) ) )
            {line.insert(i+1, " 1 ");}
        }
        // EXTRACT WEIGHT
        std::stringstream ss(line);
        int no_times{0};
        double weight{0.};
        while (ss >> key >> no_times){ weight += element_map[key] * no_times;}
        std::cout
        <<  std::fixed << std::setprecision(3) <<std::setw(9) << std::right
        << weight << '\n';
    }
    formulae.close();
    return 0;
}



                      Na(3)P(5)O(4) :   287.836
                            TeCl(4) :   269.412
                           V(2)O(5) :   181.880
                  HCONHCH(2)CH(2)OH :    88.087
                     ZnC(4)H(6)O(4) :   183.460
                 UO(2)N(2)O(6)H(2)O :   396.054
                           FeTiO(3) :   151.745
                     MgC(4)H(6)O(4) :   142.395
                       C(16)N(33)OH :   670.397
                AgSiF(6)MgOH(6)O(3) :   344.295
      NiSO(4)N(2)H(4)SO(4)H(12)O(6) :   390.963
            Tl(2)S(3)O(12)H(14)O(7) :   823.021
                             CBr(4) :   331.627
                            ZnCO(3) :   125.379
                         UO(2)CO(3) :   330.037
                         ThS(2)O(8) :   424.153
                       H(4)P(2)O(5) :   145.977
                         H(2)SeO(5) :   160.973
                      K(2)Cr(2)O(7) :   294.192
                         K(2)PtI(6) :  1034.724
Program ended with exit code: 0
I think we're all having too much fun writing proper C++ programs to do this, using a standard map as the pivotal feature to manage the table of elements. :D All our programs have similar LLOC too.

Did any of you do it the hard way, as required by the assignment?

I did. <smug>

Turns out there isn’t much difference in code size to do it the C way.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
#include <sstream>

std::ifstream openFile(std::string &name)
{
    std::ifstream stm;
    stm.open(name);
    
    if( !stm ) { std::cout << "Error\n"; }
    
    return stm;
}

template <class T>
void swap(T* xp, T* yp)
{
    T temp = *xp;
    *xp = *yp;
    *yp = temp;
}

void bubbleSort(std::string* arr_1, double *arr_2, int size)
{
    std::string temp_str;
    
    for(int i = 1; i < size; i++)
    {
        for(int j = 0; j < size; j++)
        {
            if( arr_1[j+1] < arr_1[j] ) // ASCENDING ALPHABETIC ORDER
            {
                swap(arr_1[j], arr_1[j+1]);
                swap(&arr_2[j], &arr_2[j+1]); // SYNCHRONIZE ARRAY OF DOUBLES
            }
        }
    }
    return;
}

int binarySearch(std::string arr[], int left, int right, std::string str)
{
    if (right >= left)
    {
        int mid = left + (right - left) / 2;
        
        if (arr[mid] == str)
            return mid;
        
        if (arr[mid] > str)
            return binarySearch(arr, left, mid - 1, str);
        return binarySearch(arr, mid + 1, right, str);
    }
    return -1;
}

int main()
{
    std::string element_arr[100];
    double weight_arr[100];
    int COUNT{0};
    
    std::string element_file{"element.txt"};
    std::ifstream element = openFile(element_file);
    
    // MAP & SORT THE ELEMENT & ATOMIC WEIGHTS
    while( element >> element_arr[COUNT] >> weight_arr[COUNT] )
    {
        COUNT++;
    }
    element.close();
    
    bubbleSort(element_arr, weight_arr, COUNT - 1);
    
    // NORMALIZE FORMULAE
    std::string formulae_file{"chemistry_formula.txt"};
    std::ifstream formulae = openFile(formulae_file);
    std::string line;
    char tmp;
    
    while( std::getline(formulae, line) )
    {
        std::cout << std::setw(35) << std::right << line << " : ";
        for(int i = 0; i < line.length(); i++)
        {
            tmp = line[i];
            if( tmp == '(' or tmp == ')')
            {
                line[i] = ' ';
            }
            
            if( ( isupper(tmp) and isupper(line[i+1]) )
               or ( islower(tmp) and isupper(line[i+1]) ) )
            {
                line.insert(i+1, " 1 ");
            }
        }
        
        // EXTRACT WEIGHT
        std::stringstream ss(line);
        int no_times{0};
        double weight{0.};
        int index{0};
        std::string key;
        
        while (ss >> key >> no_times)
        {
            index =  binarySearch(element_arr, 0, COUNT - 1, key);
            weight += weight_arr[index] * no_times;
        }
        std::cout
        <<  std::fixed << std::setprecision(3) <<std::setw(9) << std::right
        << weight << '\n';
    }
    formulae.close();
    return 0;
}


                      Na(3)P(5)O(4) :   287.836
                            TeCl(4) :   269.412
                           V(2)O(5) :   181.880
                  HCONHCH(2)CH(2)OH :    88.087
                     ZnC(4)H(6)O(4) :   183.460
                 UO(2)N(2)O(6)H(2)O :   396.054
                           FeTiO(3) :   151.745
                     MgC(4)H(6)O(4) :   142.395
                       C(16)N(33)OH :   670.397
                AgSiF(6)MgOH(6)O(3) :   344.295
      NiSO(4)N(2)H(4)SO(4)H(12)O(6) :   390.963
            Tl(2)S(3)O(12)H(14)O(7) :   823.021
                             CBr(4) :   331.627
                            ZnCO(3) :   125.379
                         UO(2)CO(3) :   330.037
                         ThS(2)O(8) :   424.153
                       H(4)P(2)O(5) :   145.977
                         H(2)SeO(5) :   160.973
                      K(2)Cr(2)O(7) :   294.192
                         K(2)PtI(6) :  1034.724
Program ended with exit code: 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cctype>
#include <vector>
#include <map>
using namespace std;

//======================================================================

struct Unit
{
   string atom;
   int count;
};

//======================================================================

vector<Unit> parseMolecule( const string &str )
{
   stringstream ss;

   // Convert all () to blanks and put a blank in front of every capital letter to separate components
   for ( char c : str ) 
   {
      if ( c == '(' || c == ')' ) ss << ' ';
      else if ( isupper( c ) )    ss << ' ' << c;
      else                        ss << c;
   }

   // Now stream the individual components
   vector<Unit> results;
   for ( string s; ss >> s; )
   {
      if ( isdigit( s[0] ) ) results.back().count = stoi( s );
      else                   results.push_back( { s, 1 } );
   }

   return results;
}

//======================================================================

int main()
{
   map<string,double> ram;
   string name;
   double weight;
   ifstream inelement( "Element.dat" );
   while( inelement >> name >> weight ) ram[name] = weight;

   ifstream informula( "Formula.dat" );
   string formula;
   while( getline( informula, formula ) )
   {
      double rmm = 0.0;
      for ( auto e : parseMolecule( formula ) ) rmm += e.count * ram[e.atom];
      cout << formula << " ---> " << rmm << '\n';
   }
}


Na(3)P(5)O(4) ---> 287.836
TeCl(4) ---> 269.412
V(2)O(5) ---> 181.88
HCONHCH(2)CH(2)OH ---> 89.0945
ZnC(4)H(6)O(4) ---> 183.46
UO(2)N(2)O(6)H(2)O ---> 412.053
FeTiO(3) ---> 151.745
MgC(4)H(6)O(4) ---> 142.395
C(16)N(33)OH ---> 671.405
AgSiF(6)MgOH(6)O(3) ---> 344.295
NiSO(4)N(2)H(4)SO(4)H(12)O(6) ---> 390.963
Tl(2)S(3)O(12)H(14)O(7) ---> 823.021
CBr(4) ---> 331.627
ZnCO(3) ---> 125.379
UO(2)CO(3) ---> 330.037
ThS(2)O(8) ---> 424.153
H(4)P(2)O(5) ---> 145.977
H(2)SeO(5) ---> 160.973
K(2)Cr(2)O(7) ---> 294.192
K(2)PtI(6) ---> 1034.72
Newton would be proud, homework solved by successive approximation, all without the OP having to raise a finger.
@salem c
None of the solutions presented here are usable by the OP for grade, and we all know that.
Everyone here is just having fun with an enjoyable homework prompt.

Even againtry’s latest — which actually has a binary search in it! — does not meet the basic requirement that the binary search be used to build the lookup table as well as search it later.

I can’t speak for everyone, but none of us are interested in just doing someone else’s homework for him. We’re interested in playing with a fun little thing.


These kinds of homeworks introduce a degree of complexity that the student has not had to do before now, but which is trivial for us. We are happy trying to guide the OP as long as she keeps asking questions. But we’ll feel just fine playing with our own non-conforming solutions too, using more idiomatic C++.
Topic archived. No new replies allowed.