1

I am trying to find a way to split up a string to find numbers and specific words. Here I am trying to read the number of apples and oranges. However, the way I've written this, if the word "apple" or "orange" is preceded or followed by punctuation, it won't count. For example, consider the text file:

3 apples 2 oranges
3 apples. 2 oranges.
(3 apples 2 oranges)

This program will only tally up the first line since there isn't any punctuation. I was hoping someone could show me a better approach to this problem.

#include <iostream>
#include <string>
#include <fstream>
#include<sstream>
using namespace std;

void readString(string line, int& a, int& o);
//splits the string up into substrings 

void assignValue(string str, int& a, int& o, int v);
// takes the word following the value and decides whether to assign it to       apples, oranges, or neither

int main()
{
    ifstream inStream;
    inStream.open(name_of_file);

    int apples = 0, oranges = 0;
    string line;

    while (!(inStream.eof()))
    {
        getline(inStream, line);
        readString(line, apples, oranges);
    }

    cout << "Apples:" << apples << endl;
    cout << "Oranges" << oranges << endl;

    inStream.close();

    system("pause");
    return 0;
}

   void readString(string l, int& a, int& o)
   {
       stringstream ss(l);
       string word;
       int value = 0;

       while (ss >> word)
       {
            istringstream convert(word
            if (convert >> value)                           
            {
               ss >> word;                          
               assignValue(word, a, o, value);              
            }
       }
   }

   void assignValue(string str, int& a, int& o, int v)
   {
        if (str == "apples")
        {
            a += v;
        }
        if (str == "oranges")
        {
            o += v;
        }
   }
Bendzukic
  • 35
  • 4
  • 1
    as an aside. Instead of `while (!(inStream.eof()))`, you should just use `if(inStream >> line)` as `eof` does not check for errors, only end of file. See [here](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong). – Paul Rooney Sep 08 '16 at 23:48

1 Answers1

0

It looks to me like all that's needed here is to replace any punctuation in the string to spaces, before executing your existing parsing code, which will nicely chop up the string into whitespace-delimited words.

Let's define "punctuation" as "anything other than a letter or a number".

You can use std::replace_if() in readString() before it constructs its std::stringstream:

std::replace_if(l.begin(), l.end(), [](char c) { return !isalnum(c) }, ' ');

Or, if you like to be a little bit explicit:

for (char &c:l)
{
     if (!isalnum(c))
         c=' ';
}

Now, that all punctuation is now replaced by spaces, the existing code you have there should nicely clean up after this.

A possible complication here would be if your numeric values could be fractional. Since you declared them as int, this cannot be the case. But, if you have to accept something like "4.5 apples" as input, this will require additional work, of course, since this code will happily replace the period with a space. But, that's just a mental note, to keep in mind.

Sam Varshavchik
  • 84,126
  • 5
  • 57
  • 106