splitting int from a string - c++

I have string with number on ints seperated by space delimiter. Can some one help me how to split the string into ints. I tried to use find and then substr. Is there a better way to do it ?

Use a stringsteam:
#include <string>
#include <sstream>
int main() {
std::string s = "100 123 42";
std::istringstream is( s );
int n;
while( is >> n ) {
// do something with n
}
}

This has been discussed as part of Split a string in C++?
Also, you can use boost library split function to achieve the splitting without a loop in your program.
Eg.
boost::split(epoch_vector, epoch_string, boost::is_any_of(","));

A version using boost. The stringstream version from Neil is so much simpler!
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
int main()
{
const std::string str( "20 30 40 50" );
std::vector<int> numbers;
boost::tokenizer<> tok(str);
std::transform( tok.begin(), tok.end(), std::back_inserter(numbers),
&boost::lexical_cast<int,std::string> );
// print them
std::copy( numbers.begin(), numbers.end(), std::ostream_iterator<int>(std::cout,"\n") );
}

I had some trouble when reading and converting more than one string (I found I had to clear the string stream). Here a test I made with multiple int/string conversions with read/write to an i/o file.
#include <iostream>
#include <fstream> // for the file i/o
#include <string> // for the string class work
#include <sstream> // for the string stream class work
using namespace std;
int main(int argc, char *argv[])
{
// Aux variables:
int aData[3];
string sData;
stringstream ss;
// Creation of the i/o file:
// ...
// Check for file open correctly:
// ...
// Write initial data on file:
for (unsigned i=0; i<6; ++i)
{
aData[0] = 1*i;
aData[1] = 2*i;
aData[2] = 3*i;
ss.str(""); // Empty the string stream
ss.clear();
ss << aData[0] << ' ' << aData[1] << ' ' << aData[2];
sData = ss.str(); // number-to-string conversion done
my_file << sData << endl;
}
// Simultaneous read and write:
for (unsigned i=0; i<6; ++i)
{
// Read string line from the file:
my_file.seekg(0, ios::beg);
getline (my_file, sData); // reads from start of file
// Convert data:
ss.str(""); // Empty the string stream
ss.clear();
ss << sData;
for (unsigned j = 0; j<3; ++j)
if (ss >> aData[j]) // string-to-num conversion done
;
// Write data to file:
my_file.seekp(0, ios::end);
my_file << 100+aData[0] << ' '; // appends at the end of stream.
my_file << 100+aData[1] << ' ';
my_file << 100+aData[2] << endl;
}
// R/W complete.
// End work on file:
my_file.close();
cout << "Bye, world! \n";
return 0;
}

Related

How to I delimit a string and store each part in different vectors

I have a text file that has many lines, an example is
john:student:business
may:lecturer:math
bob:student:math
how do i split them up and store them in different vectors such as:
vector1: john, may, bob
vector2: student, lecturer, student
vector3: business, math, math
my current code is:
ifstream readDetails(argv[1]);
while (getline (readEvents, line, ':')){
cout << line << endl;
}
it only splits the string up, but i could not think of any ways to separate the string and store them into vectors.
You can create a vector of vectors and play with the token index.
If the stream can sometimes have less tokens, you will need to handle that case.
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
int main() {
const int NUM_TOKENS = 3;
std::vector<std::vector<std::string>> v(NUM_TOKENS);
int token = 0;
std::string str("Mary:Had:Lamb");
std::istringstream split(str);
std::string line;
while (std::getline (split, line, ':')){
v[token++].push_back(line);
if ( token == NUM_TOKENS )
token = 0;
}
return 0;
}
This can be done using a nested vector (aka 2D vector) and nested loops. The outer loop is for splitting the input into lines, the inner loop for splitting the tokens of each line which are separated by ':'.
#include <string>
#include <sstream>
#include <vector>
int main()
{
std::istringstream in{
"john:student:business\n"
"may:lecturer:math\n"
"bob:student:math"
};
std::vector< std::vector< std::string > > v{ 3 }; // Number of tokens per line
std::string line;
// Loop over the lines
while( std::getline( in, line ) ) {
std::istringstream lineStrm{ line };
// Loop to split the tokens of the current line
for( auto& col : v ) {
std::string token;
std::getline( lineStrm, token, ':' );
col.push_back( token );
}
}
}
Live demo on Coliru.
Create vectors of strings and store your data accordingly. Without using std::istringstream, you can basically take advantage of substr() and find() that come with String class, hence:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
int main ()
{
ifstream inFile("data.txt");
string line;
vector<string> vStr1,vStr2, vStr3;
while( std::getline( inFile, line ) ){
string::size_type idx1 = line.find(":");
string::size_type idx2 = line.rfind(":");
vStr1.push_back(line.substr(0,idx1));
vStr2.push_back(line.substr(idx1+1,idx2-idx1-1));
vStr3.push_back(line.substr(idx2+1));
}
cout << "vector1: ";
for(int i(0); i < vStr1.size(); ++i ){
cout << vStr1[i] << " ";
}
cout << endl;
cout << "vector2: ";
for(int i(0); i < vStr2.size(); ++i ){
cout << vStr2[i] << " ";
}
cout << endl;
cout << "vector3: ";
for(int i(0); i < vStr3.size(); ++i ){
cout << vStr3[i] << " ";
}
cout << endl;
return 0;
}
The result is
vector1: john may bob
vector2: student lecturer student
vector3: business math math

C++ Replacing a word in an array of characters

I'm working on a problem where I need to have user input a message then replace the work "see" with "c". I wanted to read in the array message[200] and then break it down into individule words. I tried a for loop but when I concatinate it just adds the privous words. I am only to use array of characters, no strings.
const int MAX_SIZE = 200;
int main(){
char message[MAX_SIZE]; //message array the user will enter
int length; // count of message lenght
int counter, i, j; //counters for loops
char updateMessage[MAX_SIZE]; //message after txt update
//prompt user to
cout << "Please type a sentence" << endl;
cin.get(message, MAX_SIZE, '\n');
cin.ignore(100, '\n');
length = strlen(message);
//Lower all characters
for( i = 0; i < length; ++i)
{
message[i] = tolower(message[i]);
//echo back sentence
cout << "You typed: " << message << endl;
cout << "Your message length is " << length << endl;
for( counter = 0; counter <= length; ++counter)
{
updateMessage[counter] = message[counter];
if(isspace(message[counter]) || message[counter] == '\0')
{
cout << "Space Found" << endl;
cout << updateMessage << endl;
cout << updateMessage << " ** " << endl;
}
}
return 0;
}
After each space is found I would like to output one work each only.
You should really try to learn some modern C++ and standard library features, so you don't end up writing C code in C++. As an example, this is how a C++14 program makes use of standard algorithms from the library to do the job in 10-15 lines of code:
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
using namespace std::string_literals;
std::istringstream input("Hello I see you, now you see me");
std::string str;
// get the input from the stream (use std::cin if you read from console)
std::getline(input, str);
// tokenize
std::vector<std::string> words;
std::istringstream ss(str);
for(std::string word ; ss >> word; words.push_back(word));
// replace
std::replace(words.begin(), words.end(), "see"s, "c"s);
// flatten back to a string from the tokens
str.clear();
for(auto& elem: words)
{
str += elem + ' ';
}
// display the final string
std::cout << str;
}
Live on Coliru
This is not the most efficient way of doing it, as you can perform replacement in place, but the code is clear and if you don't need to save every bit of CPU cycles it performs decently.
Below is a solution that avoids the std::vector and performs the replacement in place:
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
std::istringstream input("Hello I see you, now you see me");
std::string str;
// get the input from the stream (use std::cin if you read from console)
std::getline(input, str);
// tokenize and replace in place
std::istringstream ss(str);
std::string word;
str.clear();
while (ss >> word)
{
if (word == "see")
str += std::string("c") + ' ';
else
str += word + ' ';
}
// display the final string
std::cout << str;
}
Live on Coliru

reading data file into 2d array c++

I have a text file with 2 columns and many rows. each column is separated by spaces. i need to read them to a 2D array for further calculations.
my data file looks like
0.5 0.479425539
1 0.841470985
1.5 0.997494987
2 0.909297427
2.5 0.598472144
3 0.141120008
3.5 -0.350783228
4 -0.756802495
4.5 -0.977530118
5 -0.958924275
And my feeble attempt is
#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>
#include <ctype.h>
using namespace std;
int main () {
char line,element;
std::ifstream myfile ("C:\\Users\\g\\Desktop\\test.txt");
if (myfile.is_open())
{
while ( myfile.good() )
{
getline(myfile,line);
cout << line<<endl;
_getch();
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
The problem is I'm not able to read them correctly.... its either reading the whole line... if I specify the delimiter as 'space' then, its not reading the next row.
Pls point out whats wrong. and what should i do to store the data into 2d array for further calculations.
Thank you
#include <fstream>
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
int main(int argc, char** argv) {
std::ifstream f(argv[1]);
std::string l;
std::vector<std::vector<double> > rows;
while(std::getline(f, l)) {
std::stringstream s(l);
double d1;
double d2;
if(s >> d1 >> d2) {
std::vector<double> row;
row.push_back(d1);
row.push_back(d2);
rows.push_back(row);
}
}
for(int i = 0; i < rows.size(); ++i)
std::cout << rows[i][0] << " " << rows[i][1] << '\n';
}
The last for loop shows how to use the values in the "array". The variable rows is strictly speaking not an array, but a vector of vectors. However, a vector is much safer than c-style arrays, and allows access to its elements using [].
[As I posted this I saw a very similar program posted as a response. I wrote mine independently.]
You can read the whole line into a std::string, then use std::istringstream to extract the values from the line.
A complete working program:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
int main()
{
std::ifstream file("C:\\Users\\g\\Desktop\\test.txt");
std::string line;
// Read a line of input from the file
while (std::getline(file, line))
{
// `istringstream` behaves like a normal input stream
// but can be initialized from a string
std::istringstream iss(line);
float value;
// The input operator `>>` returns the stream
// And streams can be used as a boolean value
// A stream is "true" as long as everything is okay
while (iss >> value)
{
std::cout << "Value = " << value << '\t';
}
// Flush the standard output stream and print a newline
std::cout << std::endl;
}
}
Given the contents in the file being as in the question, the first three lines of output should be:
Value = 0.5 Value = 0.479425539
Value = 1 Value = 0.841470985
Value = 1.5 Value = 0.997494987
For a 2d-array, I would use a std::vector of std::array:
#include <vector>
#include <array>
...
std::vector<std::array<float, 2>> array;
...
float value1, value2;
if (iss >> value1 >> value2)
{
std::cout << "Values = " << value1 << ", " << value2;
array.emplace_back(std::array<int, 2>{{value1, value2}});
}
Now the first line values are array[0][0] and array[0][1], and the last lines values are array[array.size() - 1][0] and array[array.size() - 1][1].
As C++ has evolved over the years, below is a Modern C++ version.
It uses auto where possible
Uses std::pair to hold 2 values (A std::pair is a specific case of a std::tuple with two elements)
Does not close file (destructor does that at end of block)
Does not read line by line, as the stream uses <space> and <enter> as delimiters
The variables have meaningful names, so the program "reads" easily,
Uses a range for loop to output the data.
Doesn't bring the whole std namespace into the code - Why is “using namespace std” considered bad practice?
.
#include <fstream>
#include <iostream>
#include <vector>
#include <utility>
int main( int argc, char** argv )
{
if ( argc < 1 )
return -1;
const auto fileName = argv[ 1 ];
std::ifstream fileToRead( fileName );
typedef std::pair< double, double > DoublesPair;
std::vector< DoublesPair > rowsOfDoublesPair;
DoublesPair doublePairFromFile;
while ( fileToRead >> doublePairFromFile.first >> doublePairFromFile.second )
{
rowsOfDoublesPair.push_back( doublePairFromFile );
}
for ( const auto row : rowsOfDoublesPair )
std::cout << row.first << " " << row.second << '\n';
}

Trying to read from a file and skip punctuation in C++, tips?

I'm trying to read from a file, and make a vector of all the words from the file. What I tried to do below is have the user input the filename, and then have the code open the file, and skip characters if they aren't alphanumeric, then input that to a file.
Right now it just closes immediately when I input the filename. Any idea what I could be doing wrong?
#include <vector>
#include <string>
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
int main()
{
string line; //for storing words
vector<string> words; //unspecified size vector
string whichbook;
cout << "Welcome to the book analysis program. Please input the filename of the book you would like to analyze: ";
cin >> whichbook;
cout << endl;
ifstream bookread;
//could be issue
//ofstream bookoutput("results.txt");
bookread.open(whichbook.c_str());
//assert(!bookread.fail());
if(bookread.is_open()){
while(bookread.good()){
getline(bookread, line);
cout << line;
while(isalnum(bookread)){
words.push_back(bookread);
}
}
}
cout << words[];
}
I think I'd do the job a bit differently. Since you want to ignore all but alphanumeric characters, I'd start by defining a locale that treats all other characters as white space:
struct digits_only: std::ctype<char> {
digits_only(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
static std::vector<std::ctype_base::mask>
rc(std::ctype<char>::table_size,std::ctype_base::space);
std::fill(&rc['0'], &rc['9']+1, std::ctype_base::digit);
std::fill(&rc['a'], &rc['z']+1, std::ctype_base::lower);
std::fill(&rc['A'], &rc['Z']+1, std::ctype_base::upper);
return &rc[0];
}
};
That makes reading words/numbers from the stream quite trivial. For example:
int main() {
char const test[] = "This is a bunch=of-words and 2#numbers#4(with)stuff to\tseparate,them, I think.";
std::istringstream infile(test);
infile.imbue(std::locale(std::locale(), new digits_only));
std::copy(std::istream_iterator<std::string>(infile),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}
For the moment, I've copied the words/numbers to standard output, but copying to a vector just means giving a different iterator to std::copy. For real use, we'd undoubtedly want to get the data from an std::ifstream as well, but (again) it's just a matter of supplying the correct iterator. Just open the file, imbue it with the locale, and read your words/numbers. All the punctuation, etc., will be ignored automatically.
The following would read every line, skip non-alpha numeric characters and add each line as an item to the output vector. You can adapt it so it outputs words instead of lines. I did not want to provide the entire solution, as this looks a bit like a homework problem.
#include <vector>
#include <sstream>
#include <string>
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
string line; //for storing words
vector<string> words; //unspecified size vector
string whichbook;
cout << "Welcome to the book analysis program. Please input the filename of the book you would like to analyze: ";
cin >> whichbook;
cout << endl;
ifstream bookread;
//could be issue
//ofstream bookoutput("results.txt");
bookread.open(whichbook.c_str());
//assert(!bookread.fail());
if(bookread.is_open()){
while(!(bookread.eof())){
line = "";
getline(bookread, line);
string lineToAdd = "";
for(int i = 0 ; i < line.size(); ++i)
{
if(isalnum(line[i]) || line[i] == ' ')
{
if(line[i] == ' ')
lineToAdd.append(" ");
else
{ // just add the newly read character to the string 'lineToAdd'
stringstream ss;
string s;
ss << line[i];
ss >> s;
lineToAdd.append(s);
}
}
}
words.push_back(lineToAdd);
}
}
for(int i = 0 ; i < words.size(); ++i)
cout << words[i] + " ";
return 0;
}

Write CSV file into vectors in C (continued)

Basically I have 14800x8 matrix that has been extracted from matlab as CSV file ("moves.mo"). I need to read this file into 14800 vectors with 8 values each.
Here is a few lines from the file:
1,2,3,4,-1,-3,-2,-4
1,2,3,5,-1,-3,-2,-5
1,2,3,6,-1,-3,-2,-6
1,2,3,7,-1,-3,-2,-7
1,2,3,8,-1,-3,-2,-8
1,2,3,9,-1,-3,-2,-9
I wrote the following code:
#include <iostream>
#include <fstream>
#include<stdio.h>
#include <string>
#include <istream>
#include <vector>
#include <sstream>
using namespace std;
int main()
{
std::fstream inputfile;
inputfile.open("moves.da");
std::vector< std::vector<int> > vectorsmovesList; //declare vector list
while (inputfile) {
std::string s;
if (!getline( inputfile, s )) break;
istringstream ss( s );
vector <int> recordmove;
while (ss)
{
if (!getline( ss, s, ',' )) break;
int recordedMoveInt = atoi(s.c_str());
recordmove.push_back( recordedMoveInt );
}
vectorsmovesList.push_back( recordmove );
}
if (!inputfile.eof())
{
cerr << "Fooey!\n";
}
It compiles but does not give me desirable output (i.e. just prints Fooey!) . I don't know why... This problem at this point is driving me insane.
Please help!
There are better ways to read integers in C++. For example:
std::string s;
if (!getline( inputfile, s )) break;
istringstream ss( s );
int recordedMove;
while (ss >> recordedMove)
{
recordmove.push_back(recordedMove);
// consume the commas between integers. note if there are no
// separating commas, you will lose some integers here.
char garbage;
ss >> garbage;
}
Also, you're not printing out your result anywhere. Here's how you would do it:
vector<vector<int> >::const_iterator ii;
for (ii = vectorsmovesList.begin(); ii != vectorsmovesList.end(); ++ii)
{
vector<int>::const_iterator jj;
for (jj = ii->begin(); jj != ii->end(); ++jj)
cout << *jj << ' ';
cout << endl;
}
Obviously, you'd do that after you've parsed and closed the CSV file.