I'm trying to read some xyz coordinates from an input file.
This is the input file I have:
input.inp
POSITIONS
1.5 2.5 1.5 C
3.2 1.5 4.5 C
1.4 4.2 3.2 C
I want to write a function that searches the input file for the string containing " C" and then starting reading the coordinates from that line. How do I do this in c++? (I don't want to search for the the word POSITIONS, as that part of the input file may change later).
ifstream file("in");
string line;
while (getline(file, line)) {
if (line.find(" C") == string::npos)
continue;
istringstream ss(line);
double x, y, z;
ss >> x >> y >> z;
if (!ss)
continue; // error
// ok
}
You should read all the line to string variable. Analyse it and if you want to read this numbers you may use stringstream(<sstream>)
string a = "";
in >> a;
//Check whether the line has C at the end or other tests and then
stringstream b(a, stringstream::in);
double c1=0, c2=0, c3=0;
b >> c1 >> c2 >> c3;
Will read the numbers from that line.
Related
I have read the data like the following
7
1 Jesse 20
1 Jess 12
1 Jess 18
3 Jess
3 Jesse
2 Jess
3 Jess
Here the 7 is the number of input lines and i have to read the space separated input in c++, How can i read those input where we don't know how to separate them. this line contains string and integers.
Here is one example, that uses operator>> and std::string:
int x;
std::string name;
int y;
int quantity;
std::cin >> quantity;
for (int i = 0; i < quantity; ++i)
{
std::cin >> x;
std::cin >> name;
std::cin >> y;
}
The above will work for all lines that have 3 fields, but not with the lines without the last field. So, we'll need to augment the algorithm:
std::string text_line;
for (i = 0; i < quantity; ++i)
{
std::getline(std::cin, text_line); // Read in the line of text
std::istringstream text_stream(text_line);
text_line >> x;
text_line >> name;
// The following statement will place the text_stream into an error state if
// there is no 3rd field, but the text_stream is not used anymore.
text_line >> y;
}
The root cause is that the missing 3rd field elements will cause the first example to be out of sync because it will read the 1st column of the next line for the 3rd field.
The second sample of code makes the correction by reading a line at a time. The input operations are restricted to the text line and will not go past the text line.
I'm trying to implement a way of reading inputs from text files to load different sets of coordinates more easily, but I've come across a bug I don't understand, where my stringstream object will stop receiving strings once one of the lines is ill-formatted.
In my output, you can see that the string is still intact when it's printed out, and then it's put into the stringstream on the very next line, but after one ill-formatted string, the stringstream stops containing anything when I print it out.
What's going on here?
Output:
This is what the text file looks like:
Method code:
ifstream pathfile(p.string());
cout << "Path file opened successfully.\n\n";
string line;
stringstream ss;
int x, y;
char comma,direction;
//Iterate all lines in the file
while(getline(pathfile,line)){
//remove all spaces from line
line.erase(remove(line.begin(), line.end(), ' '), line.end());
//skip comments and blank lines
if(line.c_str()[0] == '#' || line.empty()) continue;
//parse remaining lines
ss.str(string()); //clear stringstream
cout <<"LINE: "<<line<<endl;
ss << line;
cout <<"SS: "<<ss.str()<<endl;
if(ss >> x >> comma >> y >> comma >> direction)
cout << "X: "<<x<<" Y: "<<y<<" D: "<<direction;
else{
cout << "Ill-formatted line: ";
}
printf(" | %s\n\n", line.c_str());
}
pathfile.close();
Since the stream enters an error state when it fails to read an integer, you will need to clear the error state. To do that:
ss.clear();
The much easier thing to do is just move the definition of the stringstream into the loop:
istringstream ss(line);
if(ss >> x >> comma >> y >> comma >> direction)
// ...
I'm working on an assignment with equations, but I can't figure out how to input the different parts of the equation.
The equation is always formatted:
[double][x/y/z][sign][double][x/y/z][sign][double][x/y/z]=[double].
An example: 2.5y+4.7x+7z=46
To accomplish this, I tried using four double variables and six character variables.
double a,d,g,j;
char b,c,e,f,h,i;
so that the equation splits into the variables a b c d e f g h i, which I can then manipulate.
If there were whitespaces anywhere in the equation, I could have used istringstream to split them, but there aren't. I am not allowed to change the input file.
How can I put the numbers in doubles, and the letters/symbols in characters?
You can use istringstream and out of stream operator.
For example:
std::istringstream iss("2.5y+4.7x+7z=46");
double a,b,c,s;
char v1,v2,v3;
iss >> a; // read 1st koef
iss >> v1; // read 1st var's name
iss >> b; // read 2nd koef
iss >> v2; // read 2nd var's name
iss >> c; // read 3rd koef
iss >> v3; // read 3rd var's name
iss.ignore(); // skip '=' symbol
iss >> s; // read sum
Signs in equation is sign of relevant koefs.
I want to parse a file which describes a set of data line by line. Each datum consists of 3 or four parameters: int int float (optional) string.
I opened file as ifstream inFile and used it in a while loop
while (inFile) {
string line;
getline(inFile,line);
istringstream iss(line);
char strInput[256];
iss >> strInput;
int i = atoi(strInput);
iss >> strInput;
int j = atoi(strInput);
iss >> strInput;
float k = atoi(strInput);
iss >> strInput;
cout << i << j << k << strInput << endl;*/
}
The problem is that the last parameter is optional, so I'll probably run into errors when it is not present. How can i check in advance how many parameters are given for each datum?
Furthermore,
string line;
getline(inFile,line);
istringstream iss(line);
seems a bit reduldant, how could I simplyfiy it?
Use the idiomatic approach in this situation, and it becomes much simpler:
for (std::string line; getline(inFile, line); ) {
std::istringstream iss(line);
int i;
int j;
float k;
if (!(iss >> i >> j)) {
//Failed to extract the required elements
//This is an error
}
if (!(iss >> k)) {
//Failed to extract the optional element
//This is not an error -- you just don't have a third parameter
}
}
By the way, atoi has some highly undesired ambiguity unless 0 is not a possible value for the string you're parsing. Since atoi returns 0 when it errors, you cannot know if a return value of 0 is a successful parsing of a string with a value of 0, or if it's an error unless you do some rather laborious checking on the original string you had it parse.
Try to stick with streams, but in situations where you do need to fall back to atoi type functionality, go with the strtoX family of functions (strtoi, strtol, strtof, etc). Or, better yet, if you're using C++11, use the stoX family of functions.
You could use a string tokenizer How do I tokenize a string in C++?
In particular: https://stackoverflow.com/a/55680/2436175
Side note: you do not need to use atoi, you could simply do:
int i,j;
iss >> i >> j;
(but this wouldn't handle alone the problem of optional elements)
A little background: I am working on a sliding block puzzle for a school project and this is our first using C++ instead of Java. This is the first time I have had to implement something that reads data from a file.
I have a simple question regarding reading input from a text file.
I understand how to read the file line by line and hold each line in a string, I want to know if I can parse the string into different data types as the file is read.
Currently I am reading each line and storing them as strings in a vector for parsing later, and I know there must be a much simpler way to implement this
The first line holds 2 integers which will indicate the length and width of the grid, the following lines will have 4 integers and a char for use as arguments when creating the blocks.
My question is this, if I read the file character by character instead, is there a function I can use that will detect if the character is an integer or a char (and ignore the spaces) so I can store them immediately and create the block objects as the file is read? How would i deal with integers >10 in this case?
EDIT: Just noting I am using fstream to read the files, I am unfamiliar with other input methods
A sample input:
4 4
3 1 2 1 b
1 1 1 1 a
To detect whether a piece of string can be parsed as an integer, you just have to parse it and see if you succeed. The best function for that would probably be std::strtoul(), since it can be made to tell you how many characters it consumed, so that you can continue parsing after that. (See the man page for details.)
However, if you already know the format of your file, you can use iostream formatted extraction. This is quite straightforward:
#include <fstream>
std::ifstream infile("thefile.txt");
int n1, n2, x1, x2, x3, x4;
char c;
if (!(infile >> n1 >> n2)) { /* error, could not read first line! Abort. */ }
while (infile >> x1 >> x2 >> x3 >> x4 >> c)
{
// successfully extracted one line, data is in x1, ..., x4, c.
}
Another alternative is to read every line into a string (using std::getline), then creating a stringstream from that line, and parsing the stringstream with >>. This has the added benefit that you can discover and skip bad lines and recover, while in the direct formatted extraction I presented above, you cannot recover from any error.
If you can assert each type, I suggest using stream operators, like you would with cin.
#include <fstream>
using namespace std;
int main()
{
fstream fileStream;
fileStream.open("inputfile.txt");
int firstNumber;
fileStream >> firstNumber;
char firstChar;
fileStream >> firstChar;
}
This way, you can read by value, instead of reading by line and then parsing the line. Just read in every value you need into a variable, as you discover you need it, like that.
I would read each line into a string (as you have been doing).
Then I would read the tokens from that line into the appropriate variables.
The operator>> when applied to a stream will convert the next value in a stream into the correct type. If this is not possable it sets flags on the stream indicating failure that are easy to test.
int x;
stream >> x; // ignores white space then: reads an integer from the stream into x
char c;
stream >> c; // ignores white space then: reads an char from the stream into c
double d;
stream >> d; // ignores white space then: reads an double from the stream into d
Assuming your input:
4 4
3 1 2 1 b
1 1 1 1 a
Not knowing what the the values mean I will put my assumptions in comments.
// Assume that stream is a std::fstream already opened to you file.
std::string line1;
std::getline(stream, line1); // reads "4 4" into `line1`
std::stringstream line1stream(line1); // convert line1 into a stream for reading.
int a;
int b;
line1stream >> a >> b; // reads "4 4" from 'line1' into a (now 4) b (now 4)
if (!stream || !line1stream)
{
// failed reading the first line.
// either reading the line failed (!stream)
// or reading 2 integers from line1stream failed (!line1stream)
throw SomeException("Failed");
}
std::string line2;
std::getline(stream, line2); // reads "3 1 2 1 b" into line2
std::stringstream line2stream(line2); // convers line2 into a stream for reading.
int data[4];
char c;
line2stream >> data[0] >> data[1] >> data[2] >> data[3] >> c;
if (!stream || !line2stream)
{
// failed reading the second line.
// either reading the line failed (!stream)
// or reading 4 integers and one char from line2stream failed (!line2stream)
throw SomeException("Failed");
}
ifstreams are also istreams, so you can use the same operator >> as with std::cin.
int main()
{
std::ifstream s("test.txt");
if (s.is_open())
{
int i, j, k;
s >> i >> j >> k;
}
}
Note that this is way not the fastest way of parsing, but that is probably irrelevant to you.