//Here is my code thus far
//HERE I SIMPLY TAKE IN A FILE FULL OF NUMBERS, INCLUDING DECIMAL NUMBERS
ifstream infile;
infile.open("Numbers.txt");
if (!infile) {
cout << "Unable to open the file" << endl;
return;
}
//CREATING VECTORS TO STORE THOSE NUMBERS IN
vector<int> iNumbers;
vector<double> dNumbers;
if (infile) {
int i;
double d;
while (infile >> i && infile >> d) {
iNumbers.push_back(i);
dNumbers.push_back(d);
}
infile.close();
}
/*
NOW ATTEMPTING TO PRINT OR PLACE THOSE NUMBERS INTO TWO DIFFERENT FILES PUTTING THE INTEGERS IN integer.txt AND PUTTING THE DOUBLES IN doubles.txt
*/
ofstream integerOut("integer.txt");
vector<int>::iterator ii;
for (ii = iNumbers.begin(); ii != iNumbers.end(); ++ii)
{
if (ii = int {
}
integerOut << *ii << endl;
cout << *ii << endl;
}
integerOut.close();
ofstream doubleOut("double.txt");
vector<double>::iterator dd;
for (dd = dNumbers.begin(); dd != dNumbers.end(); ++dd)
{
doubleOut << *dd << endl;
cout << *dd << endl;
}
doubleOut.close();
}
//MY CODE ONLY GIVES ME THE FIRST TWO NUMBERS FOR MY integer.txt FILE AND THE LAST DECIMALS FOR MY double.txt. WHAT AM I DOING WRONG?
Further explanation:
I have a file named Numbers.txt with numbers containing
1
5
9.4
3
4
6.3
5
2.2
I am taking the integers and trying to place them into the interger.txt file and I am taking the doubles and placing them into the double.txt file. But in my code I am receiving for integers
1
2
9
3
4
6
5
2
when I want to receive
1
5
3
4
5
only
You can use standard algorithm std::copy. For example
#include <iostream>
#include <fstream>
#include <iterator>
#include <algorithm>
//...
std::ofstream integerOut( "integer.txt" );
if ( integerOut )
{
std::copy( iNumbers.begin(), iNumbers.end(),
std::ostream_iterator<int>( integerOut, " " ) );
}
std::ofstream doubleOut( "double.txt" );
if ( doubleOut )
{
std::copy( dNumbers.begin(), dNumbers.end(),
std::ostream_iterator<double>( doubleOut, " " ) );
}
Or you can write a code where you will control the output yourself. For example
#include <iostream>
#include <fstream>
//...
std::ofstream integerOut( "integer.txt" );
for ( int x : iNumbers )
{
if ( !( integerOut << x << ' ' ) ) break;
}
std::ofstream doubleOut( "double.txt" );
for ( double x : dNumbers )
{
if ( !( doubleOut << x << ' ' ) ) break;
}
As for the input then as I have understood two integers are followed by one double in the file. So you need to read numbers accordingly.
int i1, i2;
double d;
bool valid = true;
while ( valid )
{
if ( valid = infile >> i1 ) iNumbers.push_back( i1 );
if ( valid && ( valid = infile >> i2 ) ) iNumbers.push_back( i2 );
if ( valid && ( valid = infile >> d ) ) dNumbers.push_back( d );
}
If you do not know whether the next number in the file is integer or double you can distiguish them by the presence of the period in the number. For example
std::string value;
while ( infile >> value )
{
if ( value.find( '.' ) != std::string::npos )
{
double d = std::stod( value );
dNumbers.push_back( d );
}
else
{
int i = std::stoi( value );
iNumbers.push_back( i );
}
}
Related
I use the following set-up:
#include <bits/stdc++.h>
using namespace std;
class foo {
public:
void bar( istream &in, int n ) {
vector<tuple<int,int,int,int>> q;
int x,y,a,b;
for ( q.clear(); in >> x >> y >> a >> b; q.push_back(make_tuple(x,y,a,b)) );
assert( n == q.size() );
}
};
int main() {
stringstream ss;
for ( int i= 0; i < 100; ++i )
ss << rand() << " " << rand() << " " << rand() << " " << rand() << endl;
ss.clear(), ss.seekg(0,std::ios::beg);
(new foo())->bar(ss,100);
}
In fact, my code is more complex than this, but the idea is that I put stuff (long long ints to be exact) into a stringstream and call a function, supplying the created stringstream as istream object. The above example works fine, but in my particular case I put, say, 2 mln tuples. And the problem is that the numbers are not fully recovered at the other end, inside the foo (I get less than 2000000 numbers). Can you envision a scenario when this might happen? Can this in >> x >> y >> a >> b somehow end sooner than the input is exhausted?
EDIT: I have used this check:
if ( ss.rdstate() and std::stringstream::badbit ) {
std::cerr << "Problem in putting stuff into stringstream!\n";
assert( false );
}
Somehow, everything was passing this check.
EDIT: As I said, I do a sanity check inside main() by recovering the input-numbers using the >>-method, and indeed get back the 2 mln (tuples of) numbers.
It is just when the stringstream object gets passed to the foo, it recovers only fraction of the numbers, not all of them.
EDIT: For what it's worth, I am pasting the actual context here. Because of its dependencies, it won't compile, but at least we will be able to see the offending lines. It is the run() method that is not being able to recover the queries supplied by the main() method.
#include <iostream>
#include <algorithm>
#include <chrono>
const unsigned long long PERIOD= 0x1full;
class ExpRunnerJSONOutput : public ExperimentRunner {
std::string answers;
void set_name( std::string x ) {
this->answers= "answers."+x+".txt";
}
public:
ExpRunnerJSONOutput( query_processor *p ) : ExperimentRunner(p) {
set_name(p->method_name);
}
ExperimentRunner *setProcessor( query_processor *p) override {
ExperimentRunner::setProcessor(p);
set_name(p->method_name);
return this;
}
// in: the stream of queries
// out: where to write the results to
virtual void run( std::istream &in, std::ostream &out ) override {
node_type x,y;
value_type a,b;
unsigned long long i,j,rep_period= (16383+1)*2-1;
auto n= tree->size();
std::vector<std::tuple<node_type,node_type,value_type,value_type>> queries;
for ( queries.clear(); in >> x >> y >> a >> b; queries.push_back(std::make_tuple(x,y,a,b)) ) ;
value_type *results= new value_type[queries.size()], *ptr= results;
/* results are stored in JSON */
nlohmann::json sel;
long double total_elapsed_time= 0.00;
std::chrono::time_point<std::chrono::high_resolution_clock,std::chrono::nanoseconds> start, finish;
long long int nq= 0, it= 0;
start= std::chrono::high_resolution_clock::now();
int batch= 0;
for ( auto qr: queries ) {
x= std::get<0>(qr), y= std::get<1>(qr);
a= std::get<2>(qr), b= std::get<3>(qr);
auto ans= processor->count(x,y,a,b); nq+= ans, nq-= ans, ++nq, *ptr++= ans;
}
finish = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(finish-start);
total_elapsed_time= elapsed.count();
sel["avgtime_microsec"]= total_elapsed_time/nq*(1e-3);
out << sel << std::endl;
out.flush();
delete[] results;
}
~ExpRunnerJSONOutput() final {}
};
void runall( std::istream &in, char *res_file, ExpRunnerJSONOutput *er ) {
in.clear(), in.seekg(0,std::ios::beg);
std::string results_file= std::string(res_file);
std::ofstream out;
try {
out.open(results_file,std::ios::app);
}
catch ( std::exception &e ) {
throw e;
}
er->run(in,out), out.close();
}
using instant= std::chrono::time_point<std::chrono::steady_clock,std::chrono::nanoseconds>;
void sanity_check( std::istream &in, size_type nq ) {
node_type x,y;
value_type a,b;
size_type r= 0;
for ( ;in >> x >> y >> a >> b; ++r ) ;
assert( r == nq );
}
int main( int argc, char **argv ) {
if ( argc < 5 ) {
fprintf(stderr,"usage: ./<this_executable_name> <dataset_name> <num_queries> <result_file> K");
fflush(stderr);
return 1;
}
query_processor *processor;
std::string dataset_name= std::string(argv[1]);
auto num_queries= std::strtol(argv[2],nullptr,10);
auto K= std::strtol(argv[4],nullptr,10);
std::ifstream in;
std::ofstream logs;
try {
in.open(dataset_name+".puu");
logs.open(dataset_name+".log");
} catch ( std::exception &e ) {
throw e;
}
std::string s; in >> s;
std::vector<pq_types::value_type> w;
w.clear();
pq_types::value_type maxw= 0;
for ( auto l= 0; l < s.size()/2; ++l ) {
value_type entry;
in >> entry;
w.emplace_back(entry);
maxw= std::max(maxw,entry);
}
in.close();
const rlim_t kStackSize= s.size()*2;
struct rlimit r1{};
int result= getrlimit(RLIMIT_STACK,&r1);
if ( result == 0 ) {
if ( r1.rlim_cur < kStackSize ) {
r1.rlim_cur= kStackSize;
result= setrlimit(RLIMIT_STACK,&r1);
if ( result != 0 ) {
logs << "setrlimit returned result = " << result << std::endl;
assert( false );
}
}
}
logs << "stack limit successfully set" << std::endl;
instant start, finish;
remove(argv[3]);
auto sz= s.size()/2;
random1d_interval_generator<> rig(0,sz-1), wrig(0,maxw);
auto node_queries= rig(num_queries), weight_queries= wrig(num_queries,K);
assert( node_queries.size() == num_queries );
assert( weight_queries.size() == num_queries );
std::stringstream ss;
ss.clear(), ss.seekg(0,std::ios::beg);
for ( int i= 0; i < num_queries; ++i )
ss << node_queries[i].first << " " << node_queries[i].second << " " << weight_queries[i].first << " " << weight_queries[i].second << "\n";
ss.clear(), ss.seekg(0,std::ios::beg);
sanity_check(ss,num_queries);
start = std::chrono::steady_clock::now();
auto *er= new ExpRunnerJSONOutput(processor= new my_processor(s,w,dataset_name));
finish = std::chrono::steady_clock::now();
logit(logs,processor,start,finish);
runall(ss,argv[3],er), delete processor;
logs.close();
return 0;
}
EDIT: I was wondering if this has to do with ifstream.eof() - end of file is reached before the real end
Now, how to confirm the hypothesis -- that reading stops once we reach a byte with value 26?
EDIT: One more update. After reading things inside the foo, the rdstate() returned 4, fail() == 1 and eof() == 0. So, apparently end-of-file has not been reached.
You are not checking the state of your stream. There is an upper limit on how much you can fit in there - basically the max string size. This is discussed in detailed in this question
Check for errors as you write to the stringstream?
stringstream ss;
for (int i = 0; i < 100000000; ++i) //or some other massive number?
{
ss << rand() << " " << rand() << " " << rand() << " " << rand() << endl;
if (ss.rdstate() & stringstream::badbit)
std::cerr << "Problem!\n";
}
You may want to check specific writes of numbers.
Ultimately, I've used good old FILE * instead of istreams, and everything worked as expected. For some reason, the latter was reading only a part of the file (namely, a prefix thereof), and stopping prematurely with a fail() being true.
I have no idea why.
I'm wondering what the quickest way to parse a string of numbers into a vector of ints. My situation is that I will have millions of lines of data, formatted like this:
>Header-name
ID1 1 1 12
ID2 3 6 234
.
.
.
>Header-name
ID1 1 1 12
ID2 3 6 234
.
.
.
I would like to discard the "Header-name" field (or maybe use it for sorting later on), and then ignore the ID field and then place the remaining three ints into a vector.
I realize that I could just used boost split and then lexical cast in a couple of for loops with logic to ignore certain data, but I'm not sure if that will give me the quickest solution. I've looked at boost spirit but I don't really understand how to use it. Boost or STL are all ok.
Do you have to use boost?
I've used this function for a while. I believe I got it out of Accelerated C++ and have used it since. Your delimiter seems to be a tab, or multiple white spaces. If you pass the delimiter a " " it might work. I think it will depend on what's actually there though.
std::vector<std::string> split( const std::string& line, const std::string& del )
{
std::vector<std::string> ret;
size_t i = 0;
while ( i != line.size() ) {
while ( ( i != line.size() ) && ( line.substr(i, 1) == del ) ) {
++i;
}
size_t j = i;
while ( ( j != line.size() ) && ( line.substr(j, 1) != del ) ) {
++j;
}
if ( i != j ) {
ret.push_back( line.substr( i, j - i ) );
i = j;
}
}
return ret;
}
You can get each line with this:
int main() {
std::string line;
std::vector<std::string> lines;
while ( std::getline( std::cin, line ) ) {
lines.push_back( line );
}
for ( auto it = lines.begin(); it != lines.end(); it++ ) {
std::vector<string> vec = split( (*it) );
// Do something
}
}
You can get it to return std::vector with a quick modification.
Make each string an int with atoi( myString.c_str() )
Also you'll want to put a check in to skip the headers. Should be trivial.
Note that I've not compiled that above. ;)
On this specific problem, if you want the quickest, I would recommend manual parsing 1 char at a time. Boost Spirit would probably come as a close second and save you lots of ugly code.
Manual parsing one char at a time is key to high speed, as even well optimized converters like atoi and strtol have to deal with many different numeric representations while your example seems to imply that you are only interested in plain unsigned integers. Formatted IOs (scanf, operator<<, etc.) are very slow. Reading lines into intermediate strings will probably have a visible cost.
Your problem is simple enough to parse manually, assuming that the header lines do not contain any '\t' (and assuming that there aren't any IO or format errors):
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
std::vector<unsigned> parse(std::istream &is)
{
bool skipField = true;
char c;
unsigned value = 0;
std::vector<unsigned> result;
while (is.get(c))
{
if (('\t' == c) || ('\n' == c))
{
if (!skipField)
{
result.push_back(value);
}
skipField = ('\n' == c);
value = 0;
}
else if (!skipField)
{
value *= 10;
value += (c - '0');
}
}
return result;
}
int main()
{
const std::string data = ">Header-name\nID1\t1\t1\t12\nID2\t3\t6\t234\n";
std::istringstream is(data);
const std::vector<unsigned> v = parse(is);
for (unsigned u: v)
{
std::cerr << u << std::endl;
}
}
As always, with delightfully underspecified questions like this, there's not a lot more than just showing "a way" to do "a thing". In this case, I used Boost Spirit (because you mentioned it):
Parsing into flat containers
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>
#include <map>
std::string const input(
">Header - name1\n"
"ID1 1 1 12\n"
"ID2 3 6 234\n"
">Header - name2\n"
"ID3 3 3 14\n"
"ID4 5 8 345\n"
);
using Header = std::string;
using Container = std::vector<int>;
using Data = std::map<Header, Container>;
int main()
{
namespace qi = boost::spirit::qi;
auto f(input.begin()), l(input.end());
Data data;
bool ok = qi::phrase_parse(f, l,
*(
'>' >> qi::raw[*(qi::char_ - qi::eol)] >> qi::eol
>> *(!qi::char_('>') >> qi::omit[qi::lexeme[+qi::graph]] >> *qi::int_ >> qi::eol)
), qi::blank, data);
if (ok)
{
std::cout << "Parse success\n";
for (auto const& entry : data)
{
std::cout << "Integers read with header '" << entry.first << "':\n";
for (auto i : entry.second)
std::cout << i << " ";
std::cout << "\n";
}
}
else
{
std::cout << "Parse failed\n";
}
if (f != l)
std::cout << "Remaining input: '" << std::string(f, l) << "'\n";
}
Prints
Parse success
Integers read with header 'Header - name1':
1 1 12 3 6 234
Integers read with header 'Header - name2':
3 3 14 5 8 345
Parsing into nested containers
Of course, if you wanted separate vectors for each line (don't expect efficiency) then you can simply replace the typedef:
using Container = std::list<std::vector<int> >; // or any other nested container
// to make printing work without further change:
std::ostream& operator<<(std::ostream& os, std::vector<int> const& v)
{
os << "[";
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(os, " "));
return os << "]";
}
Prints
Parse success
Integers read with header 'Header - name1':
[1 1 12 ] [3 6 234 ]
Integers read with header 'Header - name2':
[3 3 14 ] [5 8 345 ]
You can use something like the following only instead of the string array I used you will get strings from a file
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
int main()
{
std::string s[] = { "ID1 1 1 12", "ID2 3 6 234" };
std::vector<int> v;
for ( const std::string &t : s )
{
std::istringstream is( t );
std::string tmp;
is >> tmp;
v.insert( v.end(), std::istream_iterator<int>( is ),
std::istream_iterator<int>() );
}
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The output is
1 1 12 3 6 234
As for the header then you can check whether tmp is a header and if so you will skip this record.
Here is a simplified version
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
int main()
{
std::string s[] =
{
"ID1 1 1 12",
">Header-name",
"ID2 3 6 234"
};
std::vector<int> v;
for ( const std::string &t : s )
{
std::istringstream is( t );
std::string tmp;
is >> tmp;
if ( tmp[0] == '>' ) continue;
v.insert( v.end(), std::istream_iterator<int>( is ),
std::istream_iterator<int>() );
}
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The output will be the same as above.
I am having an integer N.and next N lines contain lists that can have distinct elements from 1-100.But i am not provided length of each list.How to handle this type of input.
If say i have vector > mylist;
I need to populate this list with those lists seperated by just next line.
Say if N=3
1 2 3
4
5 6
Then mylist[0]=[1,2,3] , mylist[1]=[4] , mylist[2]=[5,6].
How to do it in c++?
Mycode : Not correct but i tried.
int main(){
int t;
cin>>t;
cin.ignore();
while(t--){
int n;
cin>>n;
cin.ignore();
lists_t lists;
std::string record;
while ( std::getline( std::cin, record ) &&
record.find_first_not_of( ' ' ) != std::string::npos && lists.size()!=n)
{
std::istringstream is( record );
lists.push_back( std::vector<int>( std::istream_iterator<int>( is ),
std::istream_iterator<int>() ) );
}
for ( const auto &l : lists )
{
for ( int x : l ) std::cout << x << ' ';
std::cout << std::endl;
}
}
}
The problem is that if i enter t=1 and n=3 then instead of following n lines it takes 4 lines and then display the data.Why ?
You can use standard function std::getline ans string stream std::stringstream and of course the container std::list itself.
Here is an example
#include <iostream>
#include <iterator>
#include <list>
#include <sstream>
#include <string>
int main()
{
std::list<std::list<int>> lst;
std::string record;
while ( std::getline( std::cin, record ) &&
record.find_first_not_of( ' ' ) != std::string::npos )
{
std::istringstream is( record );
lst.push_back( std::list<int>( std::istream_iterator<int>( is ),
std::istream_iterator<int>() ) );
}
for ( const auto &l : lst )
{
for ( int x : l ) std::cout << x << ' ';
std::cout << std::endl;
}
return 0;
}
The output is
1 2 3
4
5 6
if the input was the same lines.
If you need to enter a given number of lines then the code could look the following way
#include <iostream>
#include <iterator>
#include <list>
#include <sstream>
#include <string>
int main()
{
std::list<std::list<int>> lst;
std::string record;
size_t n;
std::cin >> n;
std::cin.ignore();
while ( n-- &&
std::getline( std::cin, record ) &&
record.find_first_not_of( ' ' ) != std::string::npos )
{
std::istringstream is( record );
lst.push_back( std::list<int>( std::istream_iterator<int>( is ),
std::istream_iterator<int>() ) );
}
for ( const auto &l : lst )
{
for ( int x : l ) std::cout << x << ' ';
std::cout << std::endl;
}
return 0;
}
The input could look as
3
1 2 3
4
5 6
I need a little more help. I have managed to convert all my chars input from a text file into digits.
Example:
Input from file:
$1,9,56#%34,9
!4.23#$4,983
Output:
1956
349
423
4983
Now, I need to take those individual digits the 1 9 5 6 and make it read as a whole number. The output would look the same but they would actually be whole numbers. Make sense? I have to do this in my outer loop. It also has to be an EOF loop. So, I know I need to take the first digit and multiply it by 10 and add the next digit then multiply all that by 10 until I reach the last number. How can I write that in an efficient non-crashing way?
The input.txt file has the input stated above.
This is what I have so far...
Any help is greatly appreciated
/*
*/
//Character Processing Algorithm
#include <fstream>
#include <iostream>
#include <cctype>
using namespace std;
char const nwln = '\n';
int main ()
{
ifstream data;
ofstream out;
char ch;
char lastch;
int sum;
data.open ("lincoln.txt"); //file for input
if (!data)
{
cout << "Error!!! Failure to Open lincoln.txt" << endl;
system ("pause");
return 1;
}
out.open ("out.txt"); //file for output
if (!out)
{
cout << "Error!!! Failure to Open out.txt" << endl;
system ("pause");
return 1;
}
data.get (ch); // priming read for end-of-file loop
while (data)
{
sum = 0;
while ((ch != nwln) && data)
{
if (isdigit(ch))
out<<ch;
if (ch == '#')
out<<endl;
{
;
}
lastch = ch;
data.get (ch); // update for inner loop
} // inner loop
if (lastch != '#')
out<<endl;
data.get (ch); // update for outer loop
} //outer loop
cout << "The End..." << endl;
data.close (); out.close ();
system ("pause");
return 0;
} //main
If you need simply to output all numbers in the standard stream std::cout (or some other stream as for example file) then you can use the following code as an example. I only substituted the file input for std::cin input in variable line. You can use file input instead of the standard stream.
Also instead of
std::ostream_iterator<char>( std::cout ),
use
std::ostream_iterator<char>( out ),
and instead of
std::cout << std::endl;
use
out << std::endl;
after the std::copy_if call.
Here is the example
#include <iostream>
#include <iterator>
#include <string>
#include <sstream>
#include <algorithm>
#include <cctype>
int main()
{
std::string line;
while ( std::getline( std::cin, line) ) // instead of std::cin use data
{
// std::cout << line << std::endl;
std::string word;
std::istringstream is( line );
while ( std::getline( is, word, '#' ) )
{
// std::cout << word << std::endl;
auto it = std::find_if( word.begin(), word.end(),
[]( char c ) { return ( std::isdigit( c ) ); } );
if ( it != word.end() )
{
std::copy_if( it, word.end(),
std::ostream_iterator<char>( std::cout ),
[]( char c ) { return ( std::isdigit( c ) ); } );
std::cout << std::endl;
}
}
}
}
Test input data is
$1,9,56#%34,9
!4.23#$4,983
The output is
1956
349
423
4983
Or you can define the lambda before its using.
#include <iostream>
#include <iterator>
#include <string>
#include <sstream>
#include <algorithm>
#include <cctype>
int main()
{
std::string line;
while ( std::getline( std::cin, line) ) // instead of std::cin use data
{
// std::cout << line << std::endl;
std::string word;
std::istringstream is( line );
while ( std::getline( is, word, '#' ) )
{
// std::cout << word << std::endl;
auto lm_IsDigit = []( char c ) { return ( std::isdigit( c ) ); };
auto it = std::find_if( word.begin(), word.end(), lm_IsDigit );
if ( it != word.end() )
{
std::copy_if( it, word.end(),
std::ostream_iterator<char>( std::cout ),
lm_IsDigit );
std::cout << std::endl;
}
}
}
}
Read the input file character by character. To check if a character is a digit, use std::isdigit. Then add the number to the back of a string.
If you need to convert a string to an integer, use std::stoi
I am reading a text file with this format:
grrr,some text,45.4321,54.22134
I just have my double valued stored in a string variable.
Why is it only giving me the first digit of the string?
If I start over with just one while loop and a text file of this new format:
21.34564
it works as it should.
The thing is, sLine has the the same value as the one when I started over. What is different is the three nested for loops that most likely is causing the problem.
Here is the code that gets me what I want:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <sstream>
using namespace std;
int main()
{
string usrFileStr,
fileStr = "test.txt", // declaring an obj string literal
sBuffer,
sLine,
str;
double dValue ;
int lineCount = 1;
int nStart;
istringstream issm;
fstream inFile; // declaring a fstream obj
// cout is the name of the output stream
cout << "Enter a file: ";
cin >> usrFileStr;
inFile.open( usrFileStr.c_str(), ios::in );
// at this point the file is open and we may parse the contents of it
while ( getline ( inFile, sBuffer ) && inFile.eof() )
{
cout << "Original String From File: " << sBuffer << endl;
cout << "Modified Str from File: " << fixed << setprecision(2)
<< dValue << endl;
}
fgetc( stdin );
return 0;
}
So there it works just like it should. But i cant get it to work inside a for loop or when i have multiple feilds in my text file...
With this code, why is it taken off the decimal?
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <sstream>
#include <errno.h>
using namespace std;
int main()
{
string usrFileStr,
myFileStr = "myFile.txt", // declaring an obj string literal
sBuffer,
sLine = "";
istringstream inStream;
int lineCount = 1;
int nStart;
double dValue = 0,
dValue2 = 0;
float fvalue;
fstream inFile; // declaring a fstream obj
// cout is the name of the output stream
cout << "Enter a file: ";
cin >> usrFileStr;
inFile.open( usrFileStr.c_str(), ios::in );
// at this point the file is open and we may parse the contents of it
if ( !inFile )
{
cout << "Not Correct " << endl;
}
while ( getline ( inFile, sBuffer ) )
{
nStart = -1 ;
for ( int x = nStart + 1; x < sBuffer.length(); x++ )
{
if ( sBuffer[ x ] == ',' )
{
nStart = x;
break;
}
cout << sBuffer[ x ];
}
for ( int x = nStart + 1; x < sBuffer.length(); x++ )
{
if ( sBuffer[ x ] == ',' )
{
nStart = x;
break;
}
cout << sBuffer[ x ];
}
for ( int x = nStart + 1; x < sBuffer.length(); x++ )
{
if ( sBuffer[ x ] == ',' )
{
nStart = x;
break;
}
sLine = sBuffer[ x ];
inStream.clear();
inStream.str( sLine );
if ( inStream >> dValue )
cout << setprecision(1) << dValue;
}
for ( int x = nStart + 1; x < sBuffer.length(); x++ )
{
if ( sBuffer[ x ] == ',' )
{
nStart = x;
break;
}
sLine = sBuffer[ x ];
inStream.clear();
inStream.str( sLine );
if ( inStream >> dValue2 )
cout << setprecision(1) << dValue2;
}
cout << ") \n";
lineCount++;
}
cout << "There are a Total of: " << lineCount -1 << " line(s) in the file."
<< endl;
inFile.clear(); // clear the file of any errors
inFile.close(); // at this point we are done with the file and may close it
fgetc( stdin );
return 0;
}
I don't have any other characters to loop over in the first code because im just reading a nice little double value.
In my second code, i have many characters to get to before the one that i want. But regardless, it is still isolated from the other characters and it is still in its own varaible. im to sick to realize what the problem is :/ although i think its the for loops.
I have also tried atof but i get a '0' where the decimal should be.
and strtod is hard because i need im not reading data into a const char *cPtr
Your code is a little tough to read. You probably want to think some point about encapsulation and breaking it up into functions.
Additionally, I would try to avoid reading in single characters and use the various functions and methods for reading data in fields - you can read a whole floating point or integer number using the >> stream extractors.
Finally, a useful skill to learn is how to use a debugger. You can step through the code and inspect the values of variables as you go.
That said, it looks like your problem is here:
if ( sBuffer[ x ] == ',' )
{
nStart = x;
break;
}
**** sLine = sBuffer[ x ];
inStream.clear();
inStream.str( sLine );
if ( inStream >> dValue2 )
cout << setprecision(1) << dValue2;
On the line marked with "****", you place exactly one character into the variable called "sLine". Having done so, you convert that one character into a double precision variable dValue2 and then output it. It should be obvious why this one character is converted into the first digit of the number you want.
Using instream>>dvalue is certainly the right way to do things. But sometimes what's right isn't always easiest or necessarily best.
We could do something like this:
int
main()
{
string s = "grrr,some text,45.4321,54.22134";
double a,b;
ASSERT_IS( 2, sscanf( s.c_str(), "%*[^,],%*[^,],%lf,%lf", & a, & b ) );
cout << setprecision(8);
SHOW(a);
SHOW(b);
}
Or perhaps something like this, while less efficient, might be easier to understand...
int
main()
{
string s = "grrr,some text,45.4321,54.22134";
vector<string> v;
StringSplit( & v, s, "," );
cout << setprecision(8);
SHOW(v);
SHOW(atof( v[2].c_str()));
SHOW(strtod(v[3].c_str(), (char**)NULL));
}
Assuming:
#define SHOW(X) cout << # X " = " << (X) f << endl
/* A quick & easy way to print out vectors... */
template<class TYPE>
inline ostream & operator<< ( ostream & theOstream,
const vector<TYPE> & theVector )
{
theOstream << "Vector [" << theVector.size() << "] {"
<< (void*)(& theVector) << "}:" << endl;
for ( size_t i = 0; i < theVector.size(); i ++ )
theOstream << " [" << i << "]: \"" << theVector[i] << "\"" << endl;
return theOstream;
}
inline void
StringSplit( vector<string> * theStringVector, /* Altered/returned value */
const string & theString,
const string & theDelimiter )
{
UASSERT( theStringVector, !=, (vector<string> *) NULL );
UASSERT( theDelimiter.size(), >, 0 );
size_t start = 0, end = 0;
while ( end != string::npos )
{
end = theString.find( theDelimiter, start );
// If at end, use length=maxLength. Else use length=end-start.
theStringVector -> push_back( theString.substr( start,
(end == string::npos) ? string::npos : end - start ) );
// If at end, use start=maxSize. Else use start=end+delimiter.
start = ( ( end > (string::npos - theDelimiter.size()) )
? string::npos : end + theDelimiter.size() );
}
}
Two points:
You might want to use sBuffer.find(',')
You set sLine to the last character before ",", is this intended to be so? You only parse single digit numbers correctly this way.