How to delete a string based on spaces - c++

I have a std::string
I want to keep the string after two spaces like in Newa and Newb
std::string a = "Command send SET Command comes here";
std::string b = "Command GET Command comes here";
std::string Newa = "SET Command comes here";
std::string Newb = "Command comes here";
what comes to my mind is that i can do std::string::find(' ') two times and use std::string::substr to get the desired result.
Can we do it in more refined manner.

The following is a more generalized approach. find_n returns an iterator past the element that matches the n-th element that needs to be searched for. It can be used to split after two spaces, three spaces, etc. You can in fact use it as a building block for other algorithms. The split function will return the input string in case the string contains less than two spaces.
#include <iostream>
template<class InputIt, class T>
InputIt find_n(InputIt first, InputIt last, const T& value, size_t n)
{
size_t count{0};
while (first != last && count < n) {
if (*first++ == value) ++count;
}
return first;
}
std::string split_after_two_spaces(const std::string& s)
{
const auto it{find_n(s.begin(), s.end(), ' ', 2)};
if (it != s.end()) {
return std::string(it, s.end());
}
return s;
}
int main()
{
const std::string a = "Command send SET Command comes here";
const std::string b = "Command GET Command comes here";
const std::string c = "Command GET";
std::cout << split_after_two_spaces(a) << '\n';
std::cout << split_after_two_spaces(b) << '\n';
std::cout << split_after_two_spaces(c) << '\n';
return 0;
}
I wanted to verify how much worse this approach would be in terms of performance compared to the straightforward double find() and substr() approach, and it turns out to be a bit faster for small strings, and it is slower for longer input strings. std::string::find() is going to be faster than std::find since it is likely to be optimized to deal with strings specifically.
Short string benchmark: http://quick-bench.com/sgKeT333zoXYBQS_1EXFzprCNrY
Longer string benchmark: http://quick-bench.com/FEhPTU4YfDPvemWMqgg4oTHZlLU
Update: The following implementation of find_n is more efficient, but also a bit more complex unfortunately. It has nicer semantics in the sense that it returns an iterator to the n-th matching element, instead of an iterator one past the n-th matching element.
template<class InputIt, class T>
InputIt find_n(InputIt first, InputIt last, const T& value, size_t n)
{
if (first != last && n > 0)
{
size_t count{0};
do
{
first = std::find(first, last, value);
}
while (first != last && ++count < n);
}
return first;
}

There's no need to construct sstream, you can just use find() function twice.
The function below can remove n first words from your string (based on spaces, but it can also be parametrized). All you need is to find the first space occurence using find, replace input string with a substring (starting from a next character after that space) and repeat the procedure depending on number of words you want to remove.
#include <iostream>
#include <string>
std::string removeWords(std::string s, int n) {
for(int i=0; i<n; ++i) {
const auto spaceIdx = s.find(' ');
s = s.substr(spaceIdx+1, s.length());
}
return s;
}
int main() {
std::cout << removeWords("Command send SET Command comes here", 2) << '\n';
std::cout << removeWords("Command GET Command comes here", 2) << '\n';
return 0;
}

You can try this, with the help of sstream and getline:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
string a = "Command send SET Command comes here";
stringstream ss(a);
string w1, w2, w3, Newa;
ss >> w1 >> w2 >> w3;
getline(ss, Newa); //get rest of the string!
cout << w3 + Newa << endl;
return 0;
}
"SET Command comes here"

Hm, maybe I have a gross misunderstanding. I see many lines of descriptions, many lines of code, votings and an accepted answer.
But normally such text replacements can always be done with a one-liner. There is a dedicated function available for such tasks: std::regex_replace.
There are no requirements regarding performance, so I would recommend to use the dedicated function. Please see the following one-liner:
#include <iostream>
#include <iterator>
#include <string>
#include <regex>
int main()
{
std::string a{"Command send SET Command comes here"};
std::regex_replace(std::ostreambuf_iterator<char>(std::cout), a.begin(), a.end(), std::regex(R"(.*? .*? (.*$))"), "$1");
return 0;
}
I guess that because if its simplicity, further explanaions are not needed.

Related

use of Range Based for loops in C++

I am trying to write a program that eliminates blank spaces using a range based for loop in C++. For eg, if the input is, "what is your name?" , the output should be "Whatisyourname?" however when i run the code below, the output it gives is "Whatisyourname?me?", why is that?
int main()
{
string s = "What is your name?";
int write_index = 0;
for (const char &c : s)
{
if (c != ' ')
{
s[write_index++] = c;
}
}
cout << s << endl;
system("pause");
}
Add after the loop the following statement
s.erase( write_index );
or
s.resize( write_index );
to remove redundant characters from the string.
The general approach to such tasks is the following
#include <algorithm>
#include <string>
//...
s.erase( std::remove( s.begin(), s.end(), ' ' ), s.end() );
The reason for this is because string s is still as long as the original string, "What is your name?". You wrote over top of every character in the string except for the last three. What you could do is erase the last three characters from the string after you're done removing the spaces. This is untested but something like this should work:
s.erase(write_index, s.length() - write_index)
Your range based for loop usage is correct. Just keep in mind that you're looping over all the input characters (as though you were looping with for (int i = 0; i < s.length(); i++), but you're not outputting as many characters as you're reading.
So the equivalent for loop would be like this:
for (int i = 0; i < s.length(); i++) {
const char& c = s[i];
if (c != ' ') {
s[write_index++] = c;
}
}
Here are two useful little functions:
template<class C, class F>
bool remove_erase_if( C& c, F&& f ) {
using std::begin; using std::end;
auto it = std::remove_if( begin(c), end(c), std::forward<F>(f) );
if ( it == c.end())
return false;
c.erase( it, c.end() );
return true;
}
template<class C, class T>
bool remove_erase( C& c, T&& t ) {
using std::begin; using std::end;
auto it = std::remove( begin(c), end(c), std::forward<T>(t) );
if ( it == c.end())
return false;
c.erase( it, c.end() );
return true;
}
these both take a container, and either a test or an element.
They then remove and erase any elements that pass the test, or equal the element.
Your code emulated the remove part of the above code, and did not do the erase part. So the characters remaining at the end ... remained.
remove (or your code) simply moves all the "kept" data to the front of the container. The stuff left over at the end ... stays there. The erase step then tells the container that the stuff after the stuff you kept should be discarded. If you don't discard it, it ... remains ... and you get your bug.
With the above two functions, you can do this:
int main() {
std::string s = "What is your name?";
remove_erase( s, ' ' );
std::cout << s << '\n';
}
and you are done.
As an aside, using namespace std; is often a bad idea. And std::endl forces a buffer-flush, so I prefer '\n'. Finally, system("pause") can be emulated by running your IDE in a mode that leaves you your command window open, instead of adding it to your code Ctrl-F5.
You can keep track of the number of spaces you have and resize the string at the end.
int main()
{
string s = "What is your name?";
int length = s.length();
int write_index = 0;
for (const char &c : s)
{
if (c != ' ')
{
s[write_index++] = c;
}
else
{
length -= 1;
}
}
s.resize(length);
cout << s << endl;
}
Try this:
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
string s = "What is your name?";
std::string aux(s.size(),' ');
int write_index = 0;
for (const char &c : s)
{
if (c != ' ')
{
aux[write_index++] = c;
}
}
cout << s << endl;
cout << aux << endl;
system("pause");
}
Now, I don't personally code C++, but this looks eerily similar to a for-each loop in C#, Java, and JavaScript; so I'll give it a go.
Let's first break down your code to see what's going on
int main() {
// creates a string object which is essentially a glorified array of chars
string s = "What is your name?";
int write_index = 0;
// for evry char "c" in the char-array "s"
for (const char &c : s) {
// if c isn't a space
if (c != ' ') {
// write c to s at index "write_index" then increment "write_index"
s[write_index++] = c;
}
}
std::cout << s << std::endl;
system("pause");
}
The logic seems good, so why does "what is your name?" turn into "whatisyourname?me?"? Simple. Because you're overwriting the existing array.
"what is your name?" is 18 characters long, and since you're only writing a non-space character to the array if it's not a space you're essentially copying characters one space left for every space in your text.
For example here's what happens after you run this code over the first 7 characters: "whatiss your name?", and after the first 12: "whatisyourur name?", and finally after all 18: "whatisyourname?me?". The length of the string never really changes.
So you got a number of options to solve this issue:
Build a new string from the old one with a string-builder (if such a thing exists in C++) and return the freshly created string.
Count the number of spaces you encounter and return a substring that is that many characters shorter (original is 18 chars - 3 spaces = new is 15 chars).
Reduce the length of the string by the required amount of characters (Thanks Yakk for this one)
This is a basic application of the copy_if algorithm from the standard library.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <iterator>
#include <string>
int main()
{
std::string s = "What is your name?";
std::copy_if(s.begin(), s.end(), std::ostream_iterator<char>(std::cout),
[](char c){ return !std::isspace(c); });
return 0;
}
outputs:
Whatisyourname?
If you actually need to remove them from the original string, then use the algorithm remove_if followed by erase.

Check if a string exists in array

For a school assignment I need to check whether a string entered by the user is stored in a pre-defined word array.
I want to implement a function to perform the check, that may look like this:
bool exists(dict words, char check) { /* how to implement this? */ }
But I have no clue whether this will work or how to implement it. Can anyone help?
Here's my code:
#include <iostream>
#include <string>
using namespace std;
struct dict {
string word;
};
int main() {
dict words[5];
words[0].word = 'abc';
words[1].word = 'bcd';
words[2].word = 'cde';
words[3].word = 'def';
words[4].word = 'efg';
char user_input[100];
cin.getline(user_input, 100);
if (...) { // how do I check if the user input is in my word array?
cout << "found\n";
}
else {
cout << "not found\n";
}
}
First of all, dict is a structure and char is type able to hold single character, so you would rather need to have:
bool exists(const dict* words, const string& check);
From this point, I would say, that:
const dict* should be changed to const vector<dict>&.
std::getline is able to read input directly into string, so no plain char array is needed.
But since it's a school assignment, I suppose, that you have some limitations (and can't use neither std::vector nor std::find, that would do the job). So:
bool exists(const dict* words, size_t count, const std::string& check)
{
for(size_t n = 0; words && (n < count); ++n)
{
if(words[n].word == check)
return true;
}
return false;
}
Example:
dict langs[3];
langs[0].word = "C++";
langs[1].word = "Java";
langs[2].word = "Python";
std::string s_1 = "Java";
std::string s_2 = "C++ 11";
printf("exists(%s) : %s\n", s_1.c_str(), exists(langs, 3, s_1) ? "yes" : "no");
printf("exists(%s) : %s\n", s_2.c_str(), exists(langs, 3, s_2) ? "yes" : "no");
Output:
exists(Java) : yes
exists(C++ 11) : no
Link to sample code.
As the other answer has already pointed out, you should add a size parameter to the function signature in order to be able to iterate the array (especially to know when to stop iteration.). Then a simple loop with a comparison will do the trick.
Note that you shouldn't normally need to use raw arrays in C++, but rather one of the containers from the standard library, e.g., std::vector. Also, you should use std::string and std::getline() for your user input, and you should fix your string literals (use double quotes "..." instead of single quotes '...'). Further, you should avoid using namespace std; conciouslessly. Have a look at the links at the end of this post for some further reading on these points.
Example code:
#include <iostream>
#include <string>
#include <vector>
bool exists(std::string const & user_input,
std::vector<std::string> const & words)
{
for (int i = 0; i < words.size(); i++)
if (user_input == words[i])
return true;
return false;
}
int main() {
std::vector<std::string> words(5);
words[0] = "abc";
words[1] = "bcd";
words[2] = "cde";
words[3] = "def";
words[4] = "efg";
std::string user_input;
std::getline(std::cin, user_input);
if (exists(user_input, words))
std::cout << "found\n";
else
std::cout << "not found\n";
}
Example output:
$ g++ test.cc && echo "abc" | ./a.out
found
The following might be beyond the scope of your school assignment, but maybe this will be helpful for future visitors to this question.
Note that an array (which std::vector is) is not the most efficient data structure to perform this sort of task, as you have to iterate the entire array to check every single item (linear complexity).
The C++ standard library also provides the container types std::set and std::unordered_set (the latter since C++11). Here the search space is organized in a special way (binary search tree: logarithmic complexity, hash table: constant complexity on average) to improve lookup time of the key type (std::string in this case).
Here's an example:
#include <iostream>
#include <string>
#include <set>
typedef std::set<std::string> set_type;
bool input_exists(std::string input, set_type const & words) {
return words.find(input) != words.end();
}
int main() {
set_type words = {"abc", "bcd", "cde", "def", "efg"};
std::string input;
if (std::getline(std::cin, input)) {
std::cout << "input: '" << input << "' ";
if (input_exists(input, words))
std::cout << "found\n";
else
std::cout << "not found\n";
}
}
Example output:
$ g++ test.cc -std=c++11
$ echo "abc" | ./a.out
input: 'abc' found
$ echo "abcdefg" | ./a.out
input: 'abcdefg' not found
For reference:
http://en.cppreference.com/w/cpp/container/vector
http://en.cppreference.com/w/cpp/string/basic_string
http://en.cppreference.com/w/cpp/string/basic_string/getline
http://en.cppreference.com/w/cpp/language/string_literal
Why is "using namespace std" considered bad practice?
http://en.wikipedia.org/wiki/Binary_search_tree
http://en.wikipedia.org/wiki/Hash_table
http://en.cppreference.com/w/cpp/container/set
http://en.cppreference.com/w/cpp/container/set/find
http://en.cppreference.com/w/cpp/container/unordered_set
http://en.cppreference.com/w/cpp/container/unordered_set/find
http://en.wikipedia.org/wiki/Computational_complexity_theory

How to change each word in a string vector to upper case

I was inquiring about reading a sequence of words and storing the values in a vector. Then proceed to change each word in the vector to uppercase and print the out put with respect to eight word to a line. I think my code is either slow or running infinitely as i can't seem to achieve an output.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
string word;
vector<string> text;
while (getline(cin, word)) {
text.push_back(word);
}
for (auto index = text.begin(); index != text.end(); ++index) {
for ( auto it = word.begin(); it != word.end(); ++it)
*it = toupper(*it);
/*cout<< index << " " << endl;*/
}
for (decltype(text.size()) i = 0; i != 8; i++)
cout << text[i] << endl;
return 0;
}
At least as far as I can tell, the idea here is to ignore the existing line structure, and write out 8 words per line, regardless of line breaks in the input data. Assuming that's correct, I'd start by just reading words from the input, paying no attention to the existing line breaks.
From there, it's a matter of capitalizing the words, writing them out, and (if you're at a multiple of 8, a new-line.
I would also use standard algorithms for most of the work, instead of writing my own loops to do the pars such as reading and writing the data. Since the pattern is basically just reading a word, modifying it, then writing out the result, it fits nicely with the std::transform algorithm.
Code to do that could look something like this:
#include <string>
#include <iostream>
#include <algorithm>
std::string to_upper(std::string in) {
for (auto &ch : in)
ch = toupper((unsigned char) ch);
return in;
}
int main() {
int count = 0;
std::transform(
std::istream_iterator<std::string>(std::cin),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout),
[&](std::string const &in) {
char sep = (++count % 8 == 0) ? '\n' : ' ';
return to_upper(in) + sep;
});
}
We could implement capitalizing each string as a second lambda, nested inside the first, but IMO, that starts to become a bit unreadable. Likewise, we could use std::tranform to implement the upper-case transformation inside of to_upper.
I'll rewrite my answer here:
Your outer for loop defines index to cycle through text, but you never use index inside it. The inner loop uses word, but word is still the last one the user entered. You should change the inner loop so that it uses index instead of word, like this:
for ( auto it = index->begin(); it != index->end(); ++it)
This is effectively an infinite loop:
while (getline(cin, word)) {
text.push_back(word);
}
getline(cin, word) reads a line (ending in '\n') from stdin, and puts it into word. It then returns cin itself (which will evaluate to true if the read was successful). You seem to be using it to get a space-delimited word, rather than a whole line, but that's not what it does. Since you put it in the condition of the while, after you enter a line, it will wait for another line.
This loop only breaks when getline fails. For example, by hitting an End of File character. I expect you're using the console and pressing Enter. In that case, you are never causing getline to fail. (If you're feeding a file into stdin, it should work.)
The typical solution to this is to have some sort of way of indicating a stop (such as an "Enter an empty line to stop" or "Write \"STOP\" to stop", and then checking for that before inserting the line into the vector). For you, the solution is to read in a SINGLE line, and then break it up into words (for example, using the sstream library).
You can detect whether the program is doing actual work (rather than waiting for more input) by viewing your CPU use. In Windows, this is CTRL+SHIFT+ESC -> Performance, and -> Processes to see your program in particular. You will find that the program isn't actually using the CPU (because it's waiting for more input).
You should try inserting print statements into your program to figure out where it gets up to. You will find it never goes past the for-loop.
Short Answer
for (string &str : vec)
{
transform(str.begin(), str.end(), str.begin(), [](char c) { return std::toupper(c); });
}
Complete working code as example:
#include <iostream>
#include <string>
#include <vector>
#include <cctype>
#include <algorithm>
using namespace std;
int main()
{
vector<string> vec;
string str;
while (cin >> str)
{
vec.push_back(str);
}
for (string &str : vec)
{
transform(str.begin(), str.end(), str.begin(), [](char c)
{ return toupper(c); });
}
for (auto str : vec)
{
cout << str << endl;
}
return 0;
}

Splitting a String in C++ (using cin)

I'm doing THIS UVa problem, which takes in the following input:
This is fun-
ny! Mr.P and I've never seen
this ice-cream flavour
before.Crazy eh?
#
This is fun-
ny! Mr.P and I've never seen
this ice-cream flavour
before.Crazy eh?
#
and produces this output:
1 1
2 3
3 2
4 3
5 3
6 1
7 1
8 1
1 1
2 3
3 2
4 3
5 3
6 1
7 1
8 1
In the input, # divides the cases. I'm supposed to get the length of each word and count the frequency of each different length (as you see in the output, a word of length 1 occurs once, length 2 occurs three times, 3 occurs twice, and so on).
My problem is this: When reading in cin, before.Crazy is counted as one word, since there is no space dividing them. It should then be as simple as splitting the string on certain punctuation ({".",",","!","?"} for example)...but C++ seems to have no simple way to split the string.
So, my question: How can I split the string and send in each returned string to my function that handles the rest of the problem?
Here's my code:
int main()
{
string input="";
while(cin.peek()!=-1)
{
while(cin >> input && input!="#")
{
lengthFrequency(input);
cout << input << " " << input.length() << endl;
}
if(cin.peek()!=-1) cout << endl;
lengthFrequencies.clear();
}
return 0;
}
lengthFrequency is a map<int,int>.
You can redefine what a stream considers to be a whitespace character using a std::locale with a custom std::ctype<char> facet. Here is corresponding code which doesn't quite do the assignment but demonstrates how to use the facet:
#include <algorithm>
#include <iostream>
#include <locale>
#include <string>
struct ctype
: std::ctype<char>
{
typedef std::ctype<char> base;
static base::mask const* make_table(char const* spaces,
base::mask* table)
{
base::mask const* classic(base::classic_table());
std::copy(classic, classic + base::table_size, table);
for (; *spaces; ++spaces) {
table[int(*spaces)] |= base::space;
}
return table;
}
ctype(char const* spaces)
: base(make_table(spaces, table))
{
}
base::mask table[base::table_size];
};
int main()
{
std::cin.imbue(std::locale(std::locale(), new ctype(".,!?")));
for (std::string s; std::cin >> s; ) {
std::cout << "s='" << s << "'\n";
}
}
Before counting the frequencies, you could parse the input string and replace all the {".",",","!","?"} characters with spaces (or whatever separation character you want to use). Then your existing code should work.
You may want to handle some characters differently. For example, in the case of before.Crazy you would replace the '.' with a space, but for something like 'ny! ' you would remove the '!' altogether because it is already followed by a space.
How about this (using the STL, comparators and functors)?
NOTE: All assumptions and explanations are in the source code itself.
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <sstream>
#include <algorithm>
#include <cctype>
#include <utility>
#include <string.h>
bool compare (const std::pair<int, int>& l, const std::pair<int, int>& r) {
return l.first < r.first;
}
//functor/unary predicate:
struct CompareFirst {
CompareFirst(int val) : val_(val) {}
bool operator()(const std::pair<int, int>& p) const {
return (val_ == p.first);
}
private:
int val_;
};
int main() {
char delims[] = ".,!?";
char noise[] ="-'";
//I'm assuming you've read the text from some file, and that information has been stored in a string. Or, the information is a string (like below):
std::string input = "This is fun-\nny, Mr.P and I've never seen\nthis ice-cream flavour\nbefore.Crazy eh?\n#\nThis is fun-\nny! Mr.P and I've never seen\nthis ice-cream flavour\nbefore.Crazy eh?\n#\n";
std::istringstream iss(input);
std::string temp;
//first split the string by #
while(std::getline(iss, temp, '#')) {
//find all the occurences of the hypens as it crosses lines, and remove the newline:
std::string::size_type begin = 0;
while(std::string::npos != (begin = temp.find('-', begin))) {
//look at the character in front of the current hypen and erase it if it's a newline, if it is - remove it
if (temp[begin+1] == '\n') {
temp.erase(begin+1, 1);
}
++begin;
}
//now, erase all the `noise` characters ("'-") as these count as these punctuation count as zero
for (int i = 0; i < strlen(noise); ++i) {
//this replaces all the hyphens and apostrophes with nothing
temp.erase(std::remove(temp.begin(), temp.end(), noise[i]), temp.end());//since hyphens occur across two lines, you need to erase newlines
}//at this point, everything is dandy for complete substitution
//now try to remove any other delim chracters by replacing them with spaces
for (int i = 0; i < strlen(delims); ++i) {
std::replace(temp.begin(), temp.end(), delims[i], ' ');
}
std::vector<std::pair<int, int> > occurences;
//initialize another input stringstream to make use of the whitespace
std::istringstream ss(temp);
//now use the whitespace to tokenize
while (ss >> temp) {
//try to find the token's size in the occurences
std::vector<std::pair<int, int> >::iterator it = std::find_if(occurences.begin(), occurences.end(), CompareFirst(temp.size()));
//if found, increment count by 1
if (it != occurences.end()) {
it->second += 1;//increment the count
}
//this is the first time it has been created. Store value, and a count of 1
else {
occurences.push_back(std::make_pair<int, int>(temp.size(), 1));
}
}
//now sort and output:
std::stable_sort(occurences.begin(), occurences.end(), compare);
for (int i = 0; i < occurences.size(); ++i) {
std::cout << occurences[i].first << " " << occurences[i].second << "\n";
}
std::cout << "\n";
}
return 0;
}
91 lines, and all vanilla C++98.
A rough outline of what I did is:
Since hyphens occur across two lines, find all hyphens and remove any newlines that follow them.
There are characters that don't add to the length of a word such as the legitimate hypenated words and the apostrophe. Find these and erase them as it makes tokenizing easier.
All the other remaining delimiters can now be found and replaced with whitespace. Why? Because we can use the whitespace to our advantage by using streams (whose default action is to skip whitespace).
Create a stream and tokenize the text via whitespace as per the previous.
Store the lengths of the tokens and their occurrences.
Sort the lengths of the tokens, and then output the token length and corresponding occurrences.
REFERENCES:
https://stackoverflow.com/a/5815875/866930
https://stackoverflow.com/a/12008126/866930

converting individual string elements to their decimal equivalents in c++

I have a string str ( "1 + 2 = 3" ). I want to obtain the individual numbers of the string in their decimal values( not ASCII ). I have tried atoi and c_str(). But both them require the entire string to consist of only numbers. I am writing my code in C++.
Any help would be great.
My challenge is to evaluate a prefix expression. I am reading from a file where each line contains a prefix expression. My code snippet to tokenize and and store the variables is as shown below. Each line of the file contains numbers and operators(+,-,*) which are separated by a space.
Ex - line = ( * + 2 3 4);
ifstream file;
string line;
file.open(argv[1]);
while(!file.eof())
{
getline(file,line);
if(line.length()==0)
continue;
else
{
vector<int> vec;
string delimiters = " ";
size_t current;
size_t next = -1;
do
{
current = next + 1;
next = line.find_first_of( delimiters, current );
if((line[next] <=57)&&(line[next] >=48))
vec.push_back(atoi((line.substr( current, next - current )).c_str()));
}while (next != string::npos);
cout << vec[0] << endl;
}
}
file.close();
In this case vec[0] prints 50 not 2.
You need to learn to delimit a string. Your delimiting characters would be mathematical operators (ie:
C: creating array of strings from delimited source string
http://www.gnu.org/software/libc/manual/html_node/Finding-Tokens-in-a-String.html
In the case of the second link, you would do something like:
const char delimiters[] = "+-=";
With this knowledge, you can create an array of strings, and call atoi() on each string to get the numeric equivalent. Then you can use the address (array index) of each delimiter to determine which operator is there.
For just things like addition and subtraction, this will be dead simple. If you want order of operations and multiplication, parentheses, etc, your process flow logic will be more complicated.
For a more in-depth example, please see this final link. A simple command-line calculator in C. That should make it crystal clear.
http://stevehanov.ca/blog/index.php?id=26
You will not fall into your if, since your next position will be at a delimiter.
string delimiters = " ";
...
next = line.find_first_of( delimiters, current );
if((line[next] <=57)&&(line[next] >=48))
...
Since your delimiters consist of " ", then line[next] will be a space character.
From the description of your problem, you are missing code that will save away your operators. There is no code to attempt to find the operators.
You don't have to assume ASCII for testing for a digit. You can use is_digit() for example, or you can compare against '9' and '0'.
When you print your vector element, you may be accessing the vector inappropriately, because no item may have ever been inserted into the array.
Don't use fin.eof() to control a loop. That function is only useful after a read has failed.
There are a number of ways to get ints from a std::string, I'm choosing std::stoi() from the C++11 standard in this case.
#include <fstream>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
typedef std::vector<int> ints;
bool is_known_operator(std::string const& token)
{
static char const* tokens[] = {"*", "/", "+", "-"};
return std::find(std::begin(tokens), std::end(tokens), token) != std::end(tokens);
}
ints tokenise(std::string const& line)
{
ints vec;
std::string token;
std::istringstream iss(line);
while (iss >> token)
{
if (is_known_operator(token))
{
std::cout << "Handle operator [" << token << "]" << std::endl;
}
else
{
try
{
auto number = std::stoi(token);
vec.push_back(number);
}
catch (const std::invalid_argument&)
{
std::cerr << "Unexpected item in the bagging area ["
<< token << "]" << std::endl;
}
}
}
return vec;
}
int main(int, const char *argv[])
{
std::ifstream file(argv[1]);
std::string line;
ints vec;
while (std::getline(file, line))
{
vec = tokenise(line);
}
std::cout << "The following " << vec.size() << " numbers were read:\n";
std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(std::cout, "\n"));
}