New Problem
boost::tokenizer<> token(line); tokenizes decimal points! How can I stop this happening?
Previous problem below is now resolved.
I am trying to grab values from a stringstream into a vector of doubles.
std::ifstream filestream;
filestream.open("data.data");
if(filestream.is_open()){
filestream.seekg(0, std::ios::beg);
std::string line;
std::vector<double> particle_state;
particle_state.resize(6);
while(filestream >> line){
boost::tokenizer<> token(line);
int i = -1;
for(boost::tokenizer<>::iterator it=token.begin(); it!=token.end(); ++it){
std::cout << *it << std::endl; // This prints the correct values from the file.
if(i == -1){
// Ommitted code
}
else{
std::stringstream ss(*it);
ss >> particle_state.at(i); // Offending code here?
}
i ++;
}
turbovector3 iPos(particle_state.at(0), particle_state.at(1), particle_state.at(2));
turbovector3 iVel(particle_state.at(3), particle_state.at(4), particle_state.at(5));
// AT THIS POINT: cout produces "(0,0,0)"
std::cout << "ADDING: P=" << iPos << " V=" << iVel << std::endl;
}
filestream.close();
}
Contents of input file:
electron(0,0,0,0,0,0);
proton(1,0,0,0,0,0);
proton(0,1,0,0,0,0);
More on turbovector3:
turbovector3 is a mathematical vector class. (The important thing is that it works - essentially it is a vector with 3 items. It is initialised using the constructor with three doubles.)
Thanks in advance for help!
EDIT Modification of code:
std::stringstream ss(*it);
if(ss.fail()){
std::cout << "FAIL!!!" << std::endl; // never happens
}
else{
std::cout << ss.str() << std::endl; // correct value pops out
}
double me;
ss >> me;
std::cout << "double:" << me << std::endl; // correct value pops out again
particle_state.at(i) = me; // This doesn't work - why?
Do you increment i in the omitted code? If not your else clause never gets called. Try outputting the stringstream buffer contents:
std::cerr << ss.str();
Also check if reading from ss actually fails:
if (ss.fail())
std::cerr << "Error reading from string stream\n";
Solution! I fluked and found this site: Link
The solution is to change the tokenizer to this:
boost::char_delimiters_separator<char> sep(false,"(),;");
boost::tokenizer<> token(line,sep);
Now it works!
Related
I wrote this piece of code to try leveldb. I am using Unix time as keys. For values that have spaces, only the last part gets saved. Here is the code. I am running Linux Kernel 4.4.0-47-generic
while (true) {
std::string note;
std::string key;
std::cout << "Test text here ";
std::cin >> note;
std::cout << std::endl;
if(note.size() == 0 || tolower(note.back()) == 'n' ) break;
key = std::to_string(std::time(nullptr));
status = db->Put(write_options, key, note);
if(!status.ok()) break;
}
std::cout << "Read texts........" << std::endl;
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
for(it->SeekToFirst(); it->Valid(); it->Next()){
std::cout << it->key().ToString() << " " << it->value().ToString() << std::endl;
}
delete db;
The issue is not in leveldb, but in the way you read the input:
std::string note;
std::cin >> note;
This will read only up to the first whitespace. It is common mistake, see for example:
reading a line from ifstream into a string variable
Guys i ran into a problem regarding accessing images in sequential order. i have images whose names change with incrementing number i.e. cube_0.jpg, cube_1.jpg, .... and so on. Now i want to access each image one-by-one and show.
Following is my code that i am playing with since 2-days and don't know how to handle this situation or what is wrong with this problem.
ostringstream s;
for (int fileNumber = 0; fileNumber<=40; fileNumber++)
{
s<<"\"cube_"<<fileNumber<<"\.jpg\""<<endl;
string fullfileName(s.str());
images[i] = fullfileName;
}
stringstream ss;
cout<<"file name"<<images[0]<<endl;
for (int file = 0; file<41; file++)
{
string str = images[file];
cout<<"str "<<str<<endl;
img_raw = imread(ss.str(), 1); // load as color image Error
cout<<"Done"<<endl<<"size"<<img_raw.size();
system("pause");
}
This code runs fine till it gets reached to "img_raw = imread(ss.str())", now this line is basically hindering me from accessing file. Since imread requires "string& filename" therefore i performed stringstream operation but nothing is working!
Any help would be greatly appreciated!
There are a few errors.
Your stringstream ss is empty. You declared it but did not fill with any values. I am pretty sure you meant imread(str, 1); instead of imread(ss.str(), 1);
In the first for loop, you are continuously printing filenames to ostringstream, so it goes like this:
0: "cube_0.jpg\"
1: "cube_0.jpg\""cube_1.jpg\"
2: "cube_0.jpg\""cube_1.jpg\""cube_2.jpg\"
...
so the ostringstream just grows and grows. ostringstream needs to be declared in the loop to be cleared for every iteration.
Edited code:
string images[41];
Mat img_raw;
for (int fileNumber = 0; fileNumber < 41; fileNumber++)
{
stringstream ss;
ss << "\cube_" << fileNumber << "\.jpg" << endl;
string fullfileName;
ss >> fullfileName;
images[fileNumber] = fullfileName;
}
for (int file = 0; file < 41; file++)
{
cout << "Loading " << images[file] << endl;
img_raw = imread(images[file], 1);
if (!img_raw.empty())
{
cout << "Successfully loaded " << images[file] << " with size " << img_raw.size() << endl;
}
else
{
cout << "Error loading file " << images[file] << endl;
}
system("pause");
}
I'm getting a segmentation fault while trying to parse a big text file. The file contains 91 529 mRNA transcripts and details about these transcripts. I've created a RefSeqTranscript object that will take these details. When I parse the file, I create a list of these objects and start putting the details into these lists. It works fine for the first 1829 transcripts and then crashes with a segmentation fault. The method I'm running is:
void TranscriptGBFFParser::ParseFile(list<RefSeqTranscript> &transcripts, const char* filepath)
{
cout << "Parsing " << filepath << "..." << endl;
ifstream infile;
infile.open(filepath);
int num = 0;
RefSeqTranscript *transcript = new RefSeqTranscript();
for(string line; getline(infile, line); )
{
in.clear();
in.str(line);
if (boost::starts_with(line, "LOCUS"))
{
if((*transcript).transcriptRefSeqAcc.size() > 0)
{
cout << (*transcript).transcriptRefSeqAcc << ":" << (*transcript).gi << ":" << (*transcript).gene.geneName << ":" << ++num << endl;
transcripts.push_back(*transcript);
delete transcript;
RefSeqTranscript *transcript = new RefSeqTranscript();
}
}
else if (boost::starts_with(line, " var"))
{
TranscriptVariation variant;
(*transcript).variations.push_back(variant);
}
//Store the definition of the transcript in the description attribute
else if (boost::starts_with(line, "DEFINITION"))
{
(*transcript).description = line.substr(12);
for(line; getline(infile, line); )
{
if(boost::starts_with(line, "ACCESSION "))
break;
(*transcript).description += line.substr(12);
}
}
//The accession number and GI number are obtained from the VERSION line
else if (boost::starts_with(line, "VERSION"))
{
string versions = line.substr(12);
vector<string> strs;
boost::split(strs, versions, boost::is_any_of( " GI:" ), boost::token_compress_on);
boost::trim_left(strs[0]);
(*transcript).transcriptRefSeqAcc = strs[0];
(*transcript).gi = atoi(strs[1].c_str());
}
//Gene information is obtained from the "gene" sections of each transcript
else if (boost::starts_with(line, " gene"))
{
for(line; getline(infile, line); )
{
if(boost::starts_with(line.substr(21), "/gene="))
{
Gene *gene = new Gene();
string name = line.substr(27);
Utilities::trim(name, '\"');
(*gene).geneName = name;
(*transcript).gene = *gene;
delete gene;
break;
}
}
(*transcript).gene.geneID = 0;
}
else if (boost::starts_with(line, " CDS"))
{
(*transcript).proteinRefSeqAcc = "";
}
else if (boost::starts_with(line, "ORIGIN"))
{
(*transcript).sequence = "";
}
}
cout << (*transcript).transcriptRefSeqAcc << ":" << (*transcript).gi << ":" << (*transcript).gene.geneName << endl;
transcripts.push_back(*transcript);
delete transcript;
cout << "No. transcripts: " << transcripts.size() << endl;
cout << flush;
infile.close();
cout << "Finished parsing " << filepath << "." << endl;
}
I'm new to C++ and don't have a great understanding of how to work with pointers etc so I'm guessing I might have done something wrong there. I don't understand why it would work for almost 2000 objects before cutting out though.
The file I'm parsing is 2.1 GB and consists of about 44 000 000 lines so any tips on how to improve the efficiency would also be much appreciated.
This is probably not the only answer, but you have a leak...
if (boost::starts_with(line, "LOCUS"))
{
if((*transcript).transcriptRefSeqAcc.size() > 0)
{
cout << (*transcript).transcriptRefSeqAcc << ":" << (*transcript).gi << ":" << (*transcript).gene.geneName << ":" << ++num << endl;
transcripts.push_back(*transcript);
delete transcript;
// LEAK!
RefSeqTranscript *transcript = new RefSeqTranscript();
}
}
You probably mean:
transcript = new RefSeqTranscript();
It's hard to say anything specific unless you provide some more details:
What line does it crashed in?
Do you really need all of those transcripts at the same time?
But I would suggest you a couple improvements:
Don't use pointer (or at least use smart pointer) for the RefSeqTranscript *transcript;
Don't use pointer for the Gene *gene;
Generally, don't use pointers unless you realy need them;
And you have a bug here:
delete transcript;
RefSeqTranscript *transcript = new RefSeqTranscript();
Since you've laready declared transcript outside the loop's body, here you hide it with new variable with the same name. This causes memory leak, and moreover, you delete an outer transcript and do not replace it with anything. So, you probably get a crash on the next iteration.
Im working on my homework assignment and I stuck because in the assignment we have to ask the user to enter a file name but also to type in either wc cc or lc (word count, character count, and line count of a file. For example, wc filename.txt. Im suppose to check the file to see if its valid or not which i understand and I know how to compare the users input to determine the different kind of function to run, but I dont understand how you could do it together. Any ideas? This is what I have so far.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
string line;
string file;
ifstream input; //input file stream
int i;
cout << "Enter a file name" << endl;
while(true){
cout << ">" ;
getline(cin,file);
input.open(file.c_str());
if (input.fail()) {
cerr << "ERROR: Failed to open file " << file << endl;
input.clear();
}
else {
i = 0;
while (getline(input, line))
if(line == "wc"){
cout << "The word count is: " << endl;
}
else if(line == "cc"){
cout << "The character count is: " << endl;
}
else if(line == "lc"){
cout << "The line count is: " << endl;
}
else if(line == "exit"){
return 0;
}
else{
cout << "----NOTE----" << endl;
cout << "Available Commands: " << endl;
cout <<"lc \"filename\"" << endl;
cout <<"cc \"filename\"" << endl;
cout <<"wc \"filename\"" << endl;
cout <<"exit" << endl;
}
}
}
return 0;
}
void wordCount(){
//TBD
}
void characterCount(){
//TBD
}
void lineCount(){
//TBD
}
You have to find the space between the command and the file name in the users input and then split the string where you find the space. Something like this
cout << "Enter a command\n";
string line;
getline(cin, line);
// get the position of the space as an index
size_t space_pos = line.find(' ');
if (space_pos == string::npos)
{
// user didn't enter a space, so error message and exit
cout << "illegal command\n";
exit(1);
}
// split the string at the first space
string cmd = line.substr(0, space_pos);
string file_name = line.substr(space_pos + 1);
This is untested code.
You could do better than this, for instance this would not work if the user entered two spaces between the command and the file name. But this kind of work rapidly gets very tedious. As this is an assignment I would be tempted to move on to more interesting things. You can always come back and improve things later if you have the time.
I think you are asking how to validate multiple arguments: the command and the file.
A simple strategy is to have function like the following:
#include <fstream> // Note: this is for ifstream below
bool argumentsInvalid(const string& command, const string & command) {
// Validate the command
// Note: Not ideal, just being short for demo
if("wc" != command && "cc" != command && "lc" != command) {
std::cout << "Invalid command" << std::endl;
return false;
}
// Validate the file
// Note: This is a cheat that uses the fact that if its valid, its open.
std::ifstream fileToRead(filename);
if(!fileToRead) {
std::cout << "Invalid file: \"" << filename << "\"" << std::endl;
return false;
}
return true;
// Note: This does rely on the ifstream destructor closing the file and would mean
// opening the file twice. Simple to show here, but not ideal real code.
}
If you want to evaluate ALL arguments before returning an error, insert a flag at the top of that function, like:
// To be set true if there is an error
bool errorFound = false;
and change all of the returns in the conditions to:
errorFound = true;
and the final return to:
return !errorFound;
Usage:
....
if(argumentsInvalid(command, filename)) {
std::cout << "Could not perform command. Skipping..." << std::endl;
// exit or continue or whatever
}
// Now do your work
Note: The specific validity tests here are over simplified.
Hi below is my function:
string Employee::get_print(void) {
string out_string;
stringstream ss;
ss << e_id << " " << type << endl;
out_string = ss.str();
return out_string;
}
e_id and type are int and they contain values from the class Employee. But when I pass them into the stringstream they just clear the string when I try to out put it. But if I don't have a int in the ss << "Some text" << endl; this output fine. What am I doing wrong =S
//Edit
Ok;
This is the calling code:
tmp = cur->get_print();
Where tmp is a string and cur is an Employee Object.
This code...
stringstream out;
out << "Test " << e_id << " " << e_type;
return out.str();
Retruns "Test " and nothing else. If I take out "Test " << my returned string is ""
I'm using GCC 4.2 on Mac OS/X 10.6.2 if that makes any difference.
I too am unable to reproduce this error. As has been mentioned, don't include the endl, as this actually appends a \n and is supposed to flush the write buffer. For this use, it is completely unnecessary and may actually lead to undesirable results...However, the code in your edit/update works just fine for me.
int main(int argc, char* argv[])
{
int e_id = 5;
int e_type = 123456;
stringstream out;
out << "Test " << e_id << " " << e_type;
cout << out.str();
return 0;
}
Produces:
Test 5 123456
My suggestions would be to double check that e_id and e_type are really just native int.
For further testing, you may want to force a cast on the values to see if it helps as such:
out << "Test " << (int)e_id << " " << (int)e_type;
Since I'm unable to reproduce this error, I'm afraid I'm unable to help any further. But best of luck to you!
Ok I have no idea what is going on with stringstream I've tried using it in other parts of my code and it doesn't work with integers. Therefore, I have reverted to using the sprintf C function:
string Employee::get_print(void) {
char out[50];
sprintf(out, "%d %d", e_id, e_type);
string output = out;
return output;
}
This returns the string which is needed.
I have moved into Netbeans and I don't have this problem. So it is an issue with Xcode.
I think the endl is not needed. You only need to write endl if you want to write a newline on a file on on std::cout.
Since you write endl, your stringstream will contain a string with 2 lines of which the second is empty. This probably confuses you. Remove the endl to get only one line.
I've got exactly the same problem - GCC and stringstream returning nothing.
As I found out, the trick is that you have to put some text data before anything else into the stringstream.
This code...
stringstream ss(stringstream::out);
ss << 3.14159;
cout << "'" << ss.str() << "'" << endl;
gets you this result:
''
But if we put a single "" inside the stringstream first...
stringstream ss(stringstream::out);
ss << "" << 3.14159;
cout << "'" << ss.str() << "'" << endl;
the result is as expected:
'3.14159'