I am trying to store some integers in a file and I am storing it with ',' as delimiter. Now when I read the file, I read the line using getline() and use tokenizer to delimit the file, However, I cannot terminate the line, I need some bool condition in getline to terminate.
while(getline(read,line)) {
std::cout<<line<<std::endl;
std::istringstream tokenizer(line);
std::string token;
int value;
while(????CONDN???) {
getline(tokenizer,token,',');
std::istringstream int_value(token);
int_value>>value;
std::cout<<value<<std::endl;
}
}
Please advice.
In your case it is enough to use getline in the same way as you do in the outer loop:
while(getline(tokenizer, token, ','))
While most likely I'd do something like this:
while(std::getline(read,line)) { // read line by line
std::replace(line.begin(), line.end(), ',', ' ' ); // get rid of commas
std::istringstream tokenizer(line);
int number;
while(tokenizer >> number) // read the ints
std::cout<<number<<std::endl;
}
And two other alternatives - that use Boost.
String Algorithms:
#include <boost/algorithm/string.hpp>
...
std::vector<std::string> strings;
boost::split(strings, "1,3,4,5,6,2", boost::is_any_of(","));
or tokenizer:
#include <boost/tokenizer.hpp>
typedef boost::char_separator<char> separator_t;
typedef boost::tokenizer<separator_t> tokenizer_t;
...
tokenizer_t tokens(line, sep);
for(tokenizer_t::iterator it = tokens.begin(); it != tokens.end(); ++it)
std::cout << *it << std::endl;
If you expect to encounter non-int, non-separator characters, e.g. 1 3 2 XXXX 4. Then you'll have to decide what to do in such a case. tokenizer >> number will stop at something that is not an int and the istringstream error flags will be set. boost::lexical_cast is also your friend:
#include <boost/lexical_cast.hpp>
...
try
{
int x = boost::lexical_cast<int>( "1a23" );
}
catch(const boost::bad_lexical_cast &)
{
std::cout << "Error: input string was not valid" << std::endl;
}
Finally, in C++11 you have the stoi/stol/stoll functions:
#include <iostream>
#include <string>
int main()
{
std::string test = "1234";
std::cout << std::stoi(str) << std::endl;
}
Related
I am learning C++ using recommended C++ books. In particular, i read about std::istringstream and saw the following example:
std::string s("some string");
std::istringstream ss(s);
std::string word;
while(ss >> word)
{
std::cout<<word <<" ";
}
Actual Output
some string
Desired Output
string some
My question is that how can we create the above std::istringstream object ss using the reversed string(that contains the word in the reverse order as shown in the desired output)? I looked at std::istringstream's constructors but couldn't find one that takes iterators so that i can pass str.back() and str.begin() instead of passing a std::string.
You can pass iterators to the istringstream constructor indirectly if you use a temporary string:
#include <sstream>
#include <iostream>
int main()
{
std::string s{"Hello World\n"};
std::istringstream ss({s.rbegin(),s.rend()});
std::string word;
while(ss >> word)
{
std::cout<<word <<" ";
}
}
Output:
dlroW olleH
Though thats reversing the string, not words. If you want to print words in reverse order a istringstream alone does not help much. You can use some container to store the extracted words and then print them in reverse:
#include <sstream>
#include <iostream>
#include <vector>
int main()
{
std::string s{"Hello World\n"};
std::istringstream ss(s);
std::string word;
std::vector<std::string> words;
while(ss >> word)
{
words.push_back(word);
}
for (auto it = words.rbegin(); it != words.rend(); ++it) std::cout << *it << " ";
}
Output:
World Hello
Since you added the c++20 tag:
#include <sstream>
#include <string>
#include <iostream>
#include <vector>
#include <ranges>
int main()
{
std::vector<std::string> vec;
std::string s("some string");
std::string word;
std::istringstream ss(s);
while(ss >> word)
{
vec.push_back(word);
}
for (auto v : vec | std::views::reverse)
{
std::cout << v << ' ';
}
}
Just a simple question, how do I include int values inside a getline()? I have searched online but couldn't find any that helps me. I am reading off a txt file. It is a row of numbers. For eg: 1,2,3,4,5. I am hoping that I can apply these int values anywhere so that the only way I can change the values is through the txt file.
I decided to use getline() but realise that I cannot use an integer. I am sorry, I am new to this C++. I hope that you can tell me where I went wrong.
Thanks!
This is my struct:
struct vacancyData {
int CCSpot;
int SNSpot;
int TPSpot;
int SCSpot;
int DRSpot;
};
This is my code:
ifstream File2;
File2.open("Vacancy.txt");
vector<vacancyData> v1;
vacancyData f;
while (getline(File2, f.CCSpot, ','))
{
getline(File2, f.SNSpot, ',');
getline(File2, f.TPSpot, ',');
getline(File2, f.SCSpot, ',');
getline(File2, f.DRSpot, '\n');
v1.push_back(f);
}
The direct answer to the question
How do I include an int inside a getline()
is: This is not possible at all.
std::getline is basically used to read a std::string from a stream, until a delimiter is found. In most cases, and that is also a default argument, the delimiter is '\n'. And with that, a complete line is read into a std::string. Please read here for a description.
If your input data is OK in most cases, then no std::getline is needed. Basic input validation can also be done directly. Please see the below example code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
struct VacancyData {
int CCSpot;
int SNSpot;
int TPSpot;
int SCSpot;
int DRSpot;
};
int main() {
// Filename
const std::string fileName{ "r:\\vacancy.txt" };
// Open file and check, if it could be opened. Use C++17 if-statement with initializer
if (std::ifstream vacancyFileStream{ fileName }; vacancyFileStream) {
// Here we will stor our data
std::vector<VacancyData> all{};
// Temps, to check, if delimiter is comma
char c1{}, c2{}, c3{}, c4{};
// This is one for loop and will read the complet file and do basic input validation
for (VacancyData vc{};
(vacancyFileStream >> vc.CCSpot >> c1 >> vc.SNSpot >> c2 >> vc.TPSpot >> c3 >> vc.SCSpot >> c4 >> vc.DRSpot) &&
c1 == ',' && c2 == ',' && c3 == ',' && c4 == ',';
all.push_back(vc))
; // Empt loop body. No statement within for loop body
// Ws there an error and could all data be read?
if (vacancyFileStream.fail() || not vacancyFileStream.eof())
std::cerr << "\n\nErorw hile reading input data\n\n";
for (const VacancyData& vc : all)
std::cout << vc.CCSpot << '\t' << vc.SNSpot << '\t' << vc.TPSpot << '\t' << vc.SCSpot << '\t' << vc.DRSpot << '\n';
}
else std::cerr << "\n\nEror: cannot open source file '" << fileName << "'\n\n";
return 0;
}
But, it is considere good practice to first read a complete line, then split it up in parts and then convert it to your structure elements.
Additionally: In C++ we often use an object oriented approach. Meaning, and objects methods, operating with the data are encapsulated in a class/struct.
In your case, we would overwrite the extractor >> and inserter operator <<.
This would then look like that (I am using C++17):
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <sstream>
struct VacancyData {
int CCSpot;
int SNSpot;
int TPSpot;
int SCSpot;
int DRSpot;
friend std::istream& operator >> (std::istream& is, VacancyData& vc) {
char c{};
return is >> vc.CCSpot >> c >> vc.SNSpot >> c >> vc.TPSpot >> c >> vc.SCSpot >> c >> vc.DRSpot;
}
friend std::ostream& operator << (std::ostream& os, const VacancyData& vc) {
return os << vc.CCSpot << '\t' << vc.SNSpot << '\t' << vc.TPSpot << '\t' << vc.SCSpot << '\t' << vc.DRSpot;
}
};
int main() {
// Filename
const std::string fileName{ "r:\\vacancy.txt" };
// Open file and check, if it could be opened. Use C++17 if-statement with initializer
if (std::ifstream vacancyFileStream{ fileName }; vacancyFileStream) {
// Here we will store our data. Read complete file and parse it
std::vector all(std::istream_iterator< VacancyData>(vacancyFileStream), {});
// Ws there an error and could all data be read?
if (vacancyFileStream.fail() || not vacancyFileStream.eof())
std::cerr << "\n\nErorw hile reading input data\n\n";
// Show output
for (const VacancyData& vc : all)
std::cout << vc << '\n';
}
else std::cerr << "\n\nEror: cannot open source file '" << fileName << "'\n\n";
return 0;
}
Now, if you want to change the reading of your data, you can use any method that you want. For example, you can read a complete line, using std::getline use any method shown below to split the input string into parts. Then you can use any method to convert that string parts into an integer for your struct. You will just change the body of your extractor operator. Nothing else will be affected. That sis the beauty of encapsulation.
Regarding: Splitting a string into tokens is a very old task. There are many many solutions available. All have different properties. Some are difficult to understand, some are hard to develop, some are more complex, slower or faster or more flexible or not.
Alternatives
Handcrafted, many variants, using pointers or iterators, maybe hard to develop and error prone.
Using old style std::strtok function. Maybe unsafe. Maybe should not be used any longer
std::getline. Most used implementation. But actually a "misuse" and not so flexible
Using dedicated modern function, specifically developed for this purpose, most flexible and good fitting into the STL environment and algortithm landscape. But slower.
Please see 4 examples in one piece of code.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <regex>
#include <algorithm>
#include <iterator>
#include <cstring>
#include <forward_list>
#include <deque>
using Container = std::vector<std::string>;
std::regex delimiter{ "," };
int main() {
// Some function to print the contents of an STL container
auto print = [](const auto& container) -> void { std::copy(container.begin(), container.end(),
std::ostream_iterator<std::decay<decltype(*container.begin())>::type>(std::cout, " ")); std::cout << '\n'; };
// Example 1: Handcrafted -------------------------------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Search for comma, then take the part and add to the result
for (size_t i{ 0U }, startpos{ 0U }; i <= stringToSplit.size(); ++i) {
// So, if there is a comma or the end of the string
if ((stringToSplit[i] == ',') || (i == (stringToSplit.size()))) {
// Copy substring
c.push_back(stringToSplit.substr(startpos, i - startpos));
startpos = i + 1;
}
}
print(c);
}
// Example 2: Using very old strtok function ----------------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Split string into parts in a simple for loop
#pragma warning(suppress : 4996)
for (char* token = std::strtok(const_cast<char*>(stringToSplit.data()), ","); token != nullptr; token = std::strtok(nullptr, ",")) {
c.push_back(token);
}
print(c);
}
// Example 3: Very often used std::getline with additional istringstream ------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};
// Put string in an std::istringstream
std::istringstream iss{ stringToSplit };
// Extract string parts in simple for loop
for (std::string part{}; std::getline(iss, part, ','); c.push_back(part))
;
print(c);
}
// Example 4: Most flexible iterator solution ------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
//
// Everything done already with range constructor. No additional code needed.
//
print(c);
// Works also with other containers in the same way
std::forward_list<std::string> c2(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
print(c2);
// And works with algorithms
std::deque<std::string> c3{};
std::copy(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {}, std::back_inserter(c3));
print(c3);
}
return 0;
}
In modern C++ you would probably do:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <sstream>
#include <regex>
// Regex for integer
const std::regex re{R"(([-+]?\d+))"};
struct VacancyData {
int CCSpot;
int SNSpot;
int TPSpot;
int SCSpot;
int DRSpot;
friend std::istream& operator >> (std::istream& is, VacancyData& vc) {
// Read a complete line and check, if that worked
if (std::string line{}; std::getline(is, line)) {
// Split the string into parts. The parts will definitely contain a integer
std::vector part(std::sregex_token_iterator(line.begin(), line.end(), re), {});
// Sanity check. Could we read 5 values?
if (not (part.size() == 5u)) {
std::cerr << "\n\nError while parsing line '" << line << '\n';
is.setstate(std::ios::failbit);
}
else {
// Splitting the string worked. We will have intergers in the parts. stoi will not fail
vc.CCSpot = std::stoi(part[0]);
vc.SNSpot = std::stoi(part[1]);
vc.TPSpot = std::stoi(part[2]);
vc.SCSpot = std::stoi(part[3]);
vc.DRSpot = std::stoi(part[4]);
}
}
return is;
}
friend std::ostream& operator << (std::ostream& os, const VacancyData& vc) {
return os << vc.CCSpot << '\t' << vc.SNSpot << '\t' << vc.TPSpot << '\t' << vc.SCSpot << '\t' << vc.DRSpot;
}
};
int main() {
// Filename
const std::string fileName{ "r:\\vacancy.txt" };
// Open file and check, if it could be opened. Use C++17 if-statement with initializer
if (std::ifstream vacancyFileStream{ fileName }; vacancyFileStream) {
// Here we will store our data. Read complete file and parse it
std::vector all(std::istream_iterator< VacancyData>(vacancyFileStream), {});
// Show output
for (const VacancyData& vc : all)
std::cout << vc << '\n';
}
else std::cerr << "\n\nEror: cannot open source file '" << fileName << "'\n\n";
return 0;
}
But, there are tons of different possible solutions. And everybody can select whatever.
All above needs to be compiles with C++17.
You can use std::getline to do this, but you need use a std::string and then to convert it to an integer. One way is to use the std::stoi function.
Example:
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
struct vacancyData {
int CCSpot;
int SNSpot;
int TPSpot;
int SCSpot;
int DRSpot;
};
// Overload operator>> for reading a "vacancyData" struct from an istream (like a file)
std::istream& operator>>(std::istream& is, vacancyData& vd) {
std::string tmp;
try {
if(std::getline(is, tmp, ',')) {
vd.CCSpot = std::stoi(tmp);
if(std::getline(is, tmp, ',')) {
vd.SNSpot = std::stoi(tmp);
if(std::getline(is, tmp, ',')) {
vd.TPSpot = std::stoi(tmp);
if(std::getline(is, tmp, ',')) {
vd.SNSpot = std::stoi(tmp);
if(std::getline(is, tmp, ',')) {
vd.SCSpot = std::stoi(tmp);
if(std::getline(is, tmp)) {
vd.DRSpot = std::stoi(tmp);
}
}
}
}
}
}
}
catch(...) { // one of the stoi calls failed
is.setstate(std::ios::failbit);
}
return is;
}
int main() {
std::ifstream File2("Vacancy.txt");
if(File2) {
// construct the vector using iterators:
std::vector<vacancyData> v1(std::istream_iterator<vacancyData>(File2),
std::istream_iterator<vacancyData>{});
// use the filled vector "v1" ...
}
}
But since there is built-in support for extracting ints directly from istreams, I suggest using that instead.
Example:
// A small support class to "eat" separators, like comma and newline
struct eater { char ch; };
std::istream& operator>>(std::istream& is, eater& e) {
if(is.peek() == e.ch) is.ignore(); // if the next char is the expected, skip it
else is.setstate(std::ios::failbit); // else set the failbit
return is;
}
std::istream& operator>>(std::istream& is, vacancyData& vd) {
eater comma{','};
eater newline{'\n'};
return is >>
vd.CCSpot >> comma >>
vd.SNSpot >> comma >>
vd.TPSpot >> comma >>
vd.SCSpot >> comma >>
vd.DRSpot >> newline;
}
I am trying to take strings as input from cin, and then push the string into a vector each time. However, my loop doesn't terminate even when I put a '\' at the end of all my input.
int main(void) {
string row;
vector<string> log;
while (cin >> row) {
if (row == "\n") {
break;
}
log.push_back(row);
}
return 0;
}
I've tried replacing the (cin >> row) with (getline(cin,row)), but it didn't make any difference. I've tried using stringstream, but I don't really know how it works. How do I go about resolving this?
As commented by #SidS, the whitespace is discarded. So you have to think about another strategy.
You could instead check if row is empty. But that will only work with std::getline:
#include <vector>
#include <string>
#include <iostream>
int main() {
std::string row;
std::vector<std::string> log;
while (std::getline(std::cin, row)) {
if (row.empty()) {
break;
}
log.push_back(row);
}
std::cout << "done\n";
}
OP, in case you want to save single words (rather than a whole line), you can use regex to single-handedly push each of them into log after input:
#include <vector>
#include <string>
#include <iostream>
#include <regex>
int main() {
const std::regex words_reg{ "[^\\s]+" };
std::string row;
std::vector<std::string> log;
while (std::getline(std::cin, row)) {
if (row.empty()) {
break;
}
for (auto it = std::sregex_iterator(row.begin(), row.end(), words_reg); it != std::sregex_iterator(); ++it){
log.push_back((*it)[0]);
}
}
for (unsigned i = 0u; i < log.size(); ++i) {
std::cout << "log[" << i << "] = " << log[i] << '\n';
}
}
Example run:
hello you
a b c d e f g
18939823
#_#_# /////
log[0] = hello
log[1] = you
log[2] = a
log[3] = b
log[4] = c
log[5] = d
log[6] = e
log[7] = f
log[8] = g
log[9] = 18939823
log[10] = #_#_#
log[11] = /////
If you want to store the tokens of one line from std::cin, separated by the standard mechanism as in the operator>> overloads from <iostream> (i.e., split by whitespace/newline), you can do it like this:
std::string line;
std::getline(std::cin, line);
std::stringstream ss{line};
const std::vector<std::string> tokens{std::istream_iterator<std::string>{ss},
std::istream_iterator<std::string>{}};
Note that this is not the most efficient solution, but it should work as expected: process only one line and use an existing mechanism to split this line into individual std::string objects.
You can't read newline by using the istream& operator >> of string. This operator ignores whitespaces and will never return the string "\n". Consider using getline instead.
#include<bits/stdc++.h>
using namespace std;
int main()
{
int i=0;
char a[100][100];
do {
cin>>a[i];
i++;
}while( strcmp(a[i],"\n") !=0 );
for(int j=0;j<i;i++)
{
cout<<a[i]<<endl;
}
return 0;
}
Here , i want to exit the do while loop as the users hits enter .But, the code doesn't come out of the loop..
The following reads one line and splits it on white-space. This code is not something one would normally expect a beginner to write from scratch. However, searching on Duckduckgo or Stackoverflow will reveal lots of variations on this theme. When progamming, know that you are probably not the first to need the functionality you seek. The engineering way is to find the best and learn from it. Study the code below. From one tiny example, you will learn about getline, string-streams, iterators, copy, back_inserter, and more. What a bargain!
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <vector>
int main() {
using namespace std;
vector<string> tokens;
{
string line;
getline(cin, line);
istringstream stream(line);
copy(istream_iterator<string>(stream),
istream_iterator<string>(),
back_inserter(tokens));
}
for (auto s : tokens) {
cout << s << '\n';
}
return 0;
}
First of all, we need to read the line until the '\n' character, which we can do with getline(). The extraction operator >> won't work here, since it will also stop reading input upon reaching a space. Once we get the whole line, we can put it into a stringstream and use cin >> str or getline(cin, str, ' ') to read the individual strings.
Another approach might be to take advantage of the fact that the extraction operator will leave the delimiter in the stream. We can then check if it's a '\n' with cin.peek().
Here's the code for the first approach:
#include <iostream> //include the standard library files individually
#include <vector> //#include <bits/stdc++.h> is terrible practice.
#include <sstream>
int main()
{
std::vector<std::string> words; //vector to store the strings
std::string line;
std::getline(std::cin, line); //get the whole line
std::stringstream ss(line); //create stringstream containing the line
std::string str;
while(std::getline(ss, str, ' ')) //loops until the input fails (when ss is empty)
{
words.push_back(str);
}
for(std::string &s : words)
{
std::cout << s << '\n';
}
}
And for the second approach:
#include <iostream> //include the standard library files individually
#include <vector> //#include <bits/stdc++.h> is terrible practice.
int main()
{
std::vector<std::string> words; //vector to store the strings
while(std::cin.peek() != '\n') //loop until next character to be read is '\n'
{
std::string str; //read a word
std::cin >> str;
words.push_back(str);
}
for(std::string &s : words)
{
std::cout << s << '\n';
}
}
You canuse getline to read ENTER, run on windows:
//#include<bits/stdc++.h>
#include <iostream>
#include <string> // for getline()
using namespace std;
int main()
{
int i = 0;
char a[100][100];
string temp;
do {
getline(std::cin, temp);
if (temp.empty())
break;
strcpy_s(a[i], temp.substr(0, 100).c_str());
} while (++i < 100);
for (int j = 0; j<i; j++)
{
cout << a[j] << endl;
}
return 0;
}
While each getline will got a whole line, like "hello world" will be read once, you can split it, just see this post.
I have the following data:
$GPVTG,,T,,M,0.00,N,0.0,K,A*13
I need to read the data, however there are blanks in between the commas, therefore I am not sure how I should read the data.
Also, how do I select GPVTG only for a group of data? For example:
GPVTG,,T,,M
GPGGA,184945.00
GPRMC,18494
GPVTG,,T,,M,0
GPGGA,184946.000,3409
I have tried using:
/* read data line */
fgets(gpsString,100,gpsHandle);
char type[10] = "GPVTG";
sscanf(gpsString," %GPVTG", &type);
if (strcmp(gpsString, "GPTVG") == 0){
printf("%s\n",gpsString);
}
Thats what i'd do
#include <iostream>
#include <vector>
#include <sstream>
#include <fstream>
#include <string>
using namespace std;
vector<string> &split(const string &s, char delim, vector<string> &elems) {
stringstream ss(s);
string item;
while (getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
vector<string> split(const string &s, char delim) {
vector<string> elems;
split(s, delim, elems);
return elems;
}
int main()
{
ifstream ifs("file.txt");
string data_string;
while ( getline( ifs, data_string ) )
{
//i think you'd want to erase first $ charachter
if ( !data_string.empty() ) data_string.erase( data_string.begin() );
//now all data put into array:
vector<string> data_array = split ( data_string, ',' );
if ( data_array[0] == "GPVTG" )
{
//do whatever you want with that data entry
cout << data_string;
}
}
return 0;
}
Should handle your task. All empty elements will be empty "" strings in array. Ask if you need anything else.
Credits for split functions belong to Split a string in C++? answer.
How about this
#include <istream>
#include <sstream>
class CSVInputStream {
public:
CSVInputStream(std::istream& ist) : input(ist) {}
std::istream& input;
};
CSVInputStream& operator>>(CSVInputStream& in, std::string& target) {
if (!in.input) return in;
std::getline(in.input, target , ',');
return in;
}
template <typename T>
CSVInputStream& operator>>(CSVInputStream& in, T& target) {
if (!in.input) return in;
std::string line;
std::getline(in.input, line , ',');
std::stringstream translator;
translator << line;
translator >> target;
return in;
}
//--------------------------------------------------------------------
// Usage follow, perhaps in another file
//--------------------------------------------------------------------
#include <fstream>
#include <iostream>
int main() {
std::ifstream file;
file.open("testcsv.csv");
CSVInputStream input(file);
std::string sentence_type;
double track_made_good;
char code;
double unused;
double speed_kph;
char speed_unit_kph;
double speed_kmh;
char speed_unit_kmh;
input >> sentence_type >> track_made_good >> code;
input >> unused >> unused;
input >> speed_kph >> speed_unit_kph;
input >> speed_kmh >> speed_unit_kmh;
std::cout << sentence_type << " - " << track_made_good << " - ";
std::cout << speed_kmh << " " << speed_unit_kmh << " - ";
std::cout << speed_kph << " " << speed_unit_kph << std::endl;;
}
This separates the comma separation from the reading of the values, and can be reused on
most other comma separated stuff.
If you want use C++ style code based on fstream:
fin.open(input);
cout << "readed";
string str;
getline(fin, str); // read one line per time