c++ parse getline in dynamic array - c++

I already asked, how I can parse single words from a stream into variables, and that works perfectly, but I don't know how many words the user will give as input. I thought I could parse it into a dynamic array, but I don't know where to start. How can I write "for each word in line"?
This is how I parse the words into the vars:
string line;
getline( cin, line );
istringstream parse( line );
string first, second, third;
parse >> first >> second >> third;
Thanks!
EDIT: Thanks to all of you, I think I get it know... and it works!

You could use std::vector<std::string> or std::list<std::string> -- they handle the resizing automatically.
istringstream parse( line );
vector<string> v;
string data;
while (parse >> data) {
v.push_back(data);
}

A possibility would be to use std::vector with istream_iterator:
#include <iostream>
#include <sstream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::istringstream in(std::string("a line from file"));
std::vector<std::string> words;
std::copy(std::istream_iterator<std::string>(in),
std::istream_iterator<std::string>(),
std::back_inserter(words));
return 0;
}
The vector will grow as required to store whatever number of words is provided by the user.

You can write as follows:
string line;
getline( cin, line );
istringstream parse( line );
string word;
while (parse >> word)
// do something with word

Since you tagged the question with foreach, here's a way to do it with with standard for_each algorithm and C++11 lambdas:
#include <string>
#include <sstream>
#include <iostream>
#include <algorithm> // for for_each
#include <vector> // vector, obviously
#include <iterator> // istream_iterator
using namespace std;
int main()
{
string line;
vector<string> vec;
getline(cin, line);
istringstream parse(line);
for_each(
istream_iterator<string>(parse),
istream_iterator<string>(),
// third argument to for_each is a lambda function
[](const string& str) {
// do whatever you want with/to the string
vec.push_back(str); // push it to the vector
}
);
}
A vector is exactly what you asked for - a dynamically resizable array that you should almost always prefer over C-style arrays. It's size need not to be known at compile time.

Related

How to convert a std::set of strings to lowercase c++ using some combination of for_each, transform, iterators and lambda?

I'm trying to convert a set of strings to lowercase without using low level loops like while and for(;;) because I'm practicing using the STL. I was thinking about using for_each and transform and lambda but I'm not really sure how they work.
#include <string>
#include <iterator>
#include <algorithm>
#include <set>
using namespace std;
int main()
{
set<string> words;
//insert a bunch of words using words.insert().....
//convert everything in words to lower case
return 0;
}
How would I convert each string in the set words using any combination of for_each, transform, iterators and lambdas?
I was thinking of doing something like: transform(words.begin(), words.end(), words.begin(), ??lambda??) however I don't know how to do the 4th parameter
You can't do something like transform(words.begin(), words.end(), words.begin(), ??lambda??),
because words.begin() would be a const iterator.
You'll have to do something like this:
set<string> words;
set<string> new_words;
transform(words.begin(), words.end(), std::inserter(new_words, new_words.begin()), [](string s) {
transform(s.begin(), s.end(), s.begin(), ::tolower);
return s;
});
return new_words;
try
std::for_each(words.begin(),words.end(),[](char & c) { c = tolower(c); });
and include cctype.

Reading a list of integer in a single input line in C++

I'm trying to read multiple integers from a single input line into an array
eg. Input: 100 200 300 400, so the array is: a[0] = 100, a[1] = 200, a[2] = 300, a[3] = 400
The thing is, the number of integers are unknown, so the size of the array is unknown.
You should use a container that automatically resizes itself, such as std::vector.
For example, something like this:
#include <string>
#include <iostream>
#include <sstream>
#include <utility>
#include <iterator>
std::string line;
getline(instream, line);
std::istringstream this_line(line);
std::istream_iterator<int> begin(this_line), end;
std::vector<int> values(begin, end);
You could use std::vector for this:
std::vector<int> myVector;
std::string line;
std::getline(std::cin, line);
std::istringstream os(line);
int i;
while(os >> i)
myVector.push_back(i);
This code requires following includes: <iostream>, <string>, <sstream> and <vector>.
Inserters and stream iterators can do this nicely:
#include <iterator>
#include <vector>
#include <iostream>
#include <algorithm>
std::vector<int> numbers;
std::copy(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::back_inserter(numbers));
Or, as #Ben Voigt has it, construct the vector from the input in one go (if that's an option):
std::vector numbers(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>());
You can replace std::cin by a suitable string stream if your input requirements are more complex.

How to get a string of union set from a vector string?

I have a vector string filled with some file extensions as follows:
vector<string> vExt;
vExt.push_back("*.JPG;*.TGA;*.TIF");
vExt.push_back("*.PNG;*.RAW");
vExt.push_back("*.BMP;*.HDF");
vExt.push_back("*.GIF");
vExt.push_back("*.JPG");
vExt.push_back("*.BMP");
I now want to get a string of union set from the above-mentioned vector string, in which each file extension must be unique in the resulting string. As for my given example, the resulting string should take the form of "*.JPG;*.TGA;*.TIF;*.PNG;*.RAW;*.BMP;*.HDF;*.GIF".
I know that std::unique can remove consecutive duplicates in range. It con't work with my condition. Would you please show me how to do that? Thank you!
See it live here: http://ideone.com/0fmy0 (FIXED)
#include <iostream>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <vector>
#include <set>
int main()
{
std::vector<std::string> vExt;
vExt.push_back("*.JPG;*.TGA;*.TIF");
vExt.push_back("*.PNG;*.RAW");
vExt.push_back("*.BMP;*.HDF");
vExt.push_back("*.GIF");
vExt.push_back("*.JPG");
vExt.push_back("*.BMP");
std::stringstream ss;
std::copy(vExt.begin(), vExt.end(),
std::ostream_iterator<std::string>(ss, ";"));
std::string element;
std::set<std::string> unique;
while (std::getline(ss, element, ';'))
unique.insert(unique.end(), element);
std::stringstream oss;
std::copy(unique.begin(), unique.end(),
std::ostream_iterator<std::string>(oss, ";"));
std::cout << oss.str() << std::endl;
return 0;
}
output:
*.BMP;*.GIF;*.HDF;*.JPG;*.PNG;*.RAW;*.TGA;*.TIF;
I'd tokenize each string into constituent parts (using semicolon as the separator), and stick the resulting tokens into a set. The resultant contents of that set is what you're looking for.
You need to parse the strings that contain multiple file extensions and then push them into the vector. After that std::unique will do what you want. Have a look at the Boost.Tokenizer class, that should make this trivial.

Random Integer List

If I had a list of integers separated by a space on one line (eg: 50 34 1 3423 5 345) then what would be the best way of making each of them a separate integer variable - collecting the list of integers with cin?
#include <iostream>
#include <vector>
#include <iterator>
std::vector<int> ints;
std::copy(std::istream_iterator<int>(cin),
std::istream_iterator<int>(),
std::back_inserter(ints));
Done. If you really need to explicetely read line-wise:
#include <sstream>
#include <iostream>
#include <vector>
#include <iterator>
std::string singleline;
std::istringstream iss; // out of loop for performance
while (std::getline(cin, singleline))
{
iss.str(singleline);
std::copy(std::istream_iterator<int>(iss),
std::istream_iterator<int>(),
std::back_inserter(ints));
}
An istream_iterator<int> will repeatedly apply operator>>(int&) to the referenced stream (until the end of the stream). By default this will silently ignore whitespace, and it will throw an exception if the input operation failed (e.g. non-integer input is encountered)
The back_inserter is an output iterator that you can use with all container types (like vector) that support the .push_back operation. So in fact what is written there in STL algorithmese is similar to
std::vector<int> ints;
while (iss>>myint)
{
ints.push_back(myint);
}
In follow-up to sehe's answer, here's how you'd do it a little more verbosely (ahem).
The algorithms sehe used basically do this internally. This answer is included mostly for clarity.
#include <iostream>
#include <vector>
int main()
{
std::vector<int> myInts;
int tmp;
while (std::cin >> tmp) {
myInts.push_back(tmp);
}
// Now `myInts` is a vector containing all the integers
}
Live example.
Have a look at the man pages for strtok( ) and atoi( )

How do I alter this tokenization process to work on a text file with multiple lines?

I'm working this source code:
#include <string>
#include <vector>
#include <iostream>
#include <istream>
#include <ostream>
#include <iterator>
#include <sstream>
#include <algorithm>
int main()
{
std::string str = "The quick brown fox";
// construct a stream from the string
std::stringstream strstr(str);
// use stream iterators to copy the stream to the vector as whitespace separated strings
std::istream_iterator<std::string> it(strstr);
std::istream_iterator<std::string> end;
std::vector<std::string> results(it, end);
// send the vector to stdout.
std::ostream_iterator<std::string> oit(std::cout);
std::copy(results.begin(), results.end(), oit);
}
To, instead of tokenizing a single line and putting it into the vector results, it tokenizes a group of lines taken from this text file and puts the resulting words into a single vector .
Text File:
Munroe states there is no particular meaning to the name and it is simply a four-letter word without a phonetic pronunciation, something he describes as "a treasured and carefully-guarded point in the space of four-character strings." The subjects of the comics themselves vary. Some are statements on life and love (some love strips are simply art with poetry), and some are mathematical or scientific in-jokes.
So far, I'm only clear that I need to use a
while (getline(streamOfText, readTextLine)){}
to get the loop running.
But I don't think this would work:
while (getline(streamOfText, readTextLine)) {
cout << readTextLine << endl;
// construct a stream from the string
std::stringstream strstr(readTextLine);
// use stream iterators to copy the stream to the vector as whitespace separated strings
std::istream_iterator it(strstr);
std::istream_iterator end;
std::vector results(it, end);
/*HOw CAN I MAKE THIS INSIDE THE LOOP WITHOUT RE-DECLARING AND USING THE CONSTRUCTORS FOR THE ITERATORS AND VECTOR? */
// send the vector to stdout.
std::ostream_iterator<std::string> oit(std::cout);
std::copy(results.begin(), results.end(), oit);
}
Yes, then you have one whole line in readTextLine. Is it that what you wanted in that loop? Then instead of constructing the vector from the istream iterators, copy into the vector, and define the vector outside the loop:
std::vector<std::string> results;
while (getline(streamOfText, readTextLine)){
std::istringstream strstr(readTextLine);
std::istream_iterator<std::string> it(strstr), end;
std::copy(it, end, std::back_inserter(results));
}
You actually don't need to read a line into the string first, if all you need is all words from a stream, and no per-line processing. Just read from the other stream directly like you did in your code. It will not only read words from one line, but from the whole stream, until the end-of-file:
std::istream_iterator<std::string> it(streamOfText), end;
std::vector<std::string> results(it, end);
To do all that manually, like you ask for in the comments, do
std::istream_iterator<std::string> it(streamOfText), end;
while(it != end) results.push_back(*it++);
I recommend you to read a good book on this. It will show you much more useful techniques i think. C++ Standard library by Josuttis is a good book.