I have to read some data from an input stream, run it through some filters, and then display the context on screen. I'm working with Windows and currently stuck on this. I'm having a hard time understanding the I/O streams.
I don't know what I should do after passing the data through the first filter because currently, the second function calculates 0 chars?
main:
std::ifstream data("somedata.txt");
whitesprem(data);
calc_chars(data);
whitesprem:
// removes extra white spaces
void whitesprem(std::ifstream& fff) {
std::string line;
while(std::getline(fff, line)){
std::regex rgx("\\s{2,}");
line = std::regex_replace(line, rgx, " ")
//How to move on?
}
}
I'd consume each line inside your whiteprem(). Another approach could be to just copy the data to another string stream from the file stream and use the new stream in the rest of the program.
Probably you intend to do something like this:
void whiteprem(std::ifstream& ff, std::stringstream &update){
std::string line;
while(std::getline(fff, line)){
std::regex rgx("\\s{2,}");
line = std::regex_replace(line, rgx, " ")
//How to move on?
update << line << std::endl;
}
}
int main(){
std::ifstream data("somedata.txt");
std::stringstream ss;
whitesprem(data, ss);
calc_chars(ss);
}
Related
I've made a simple program. I'm reading a text file in the same folder as the program. The file only has one line: " v 1.0 2.0 3.0".
Problem:
When I initialize a stringstream instance ss with a string line, and I use the erase() function to try to remove the character 'v' from the string, it is not working. The MSVC consoles shows the same line of string:
If I remove the .erase(0,1) function, the output is the same.
How could this happen? It should remove the character v. I learn this through the OpenGL's obj loader tutorial, and they can remove it.
Code
#include <sstream>
#include <fstream>
#include <iostream>
int main()
{
std::ifstream filestream("textfile.txt", std::ios::in);
std::string line = "";
while (!filestream.eof())
{
std::getline(filestream, line);
std::cout <<"getline std::string "<< line.c_str()<<std::endl;
std::stringstream ss(line.erase(0,1));
std::cout << "stringstream: " << ss.str() << std::endl;
}
}
After some testing, I found the reason. I made a low level mistake.
I should use a text editor that can show all the hiden blank spaces.
It looks like that there is an empty character since the initializtion of stringstream ss.
And if I remove one more characters, then it is okay.
int main()
{
std::ifstream filestream("textfile.txt", std::ios::in);
std::string line;
while (!filestream.eof())
{
std::getline(filestream, line);
std::cout <<"getline std::string"<< line.c_str()<<std::endl;
std::stringstream ss(line.erase(0,2));
std::cout << "stringstream:" << ss.str() << std::endl;
}
}
Is it possible that book writer of the opengl book made a typo? They use
erase(0,1) for "v" for vertices data, and then use erase(0,2) for "f" for the face data
That is the mistake for not using a good text editor
I'm reading in CSV files and trying to remove the outer quotes. I'm currently using this:
std::string cell = "input "my quoted" cell"; // from `getline()`
std::stringstream cs;
std::string unquoted;
cs << cell;
cs >> std::quoted(unquoted);
This does work, but it seems to me that this is very inefficient, since I have to create a std::stringstream each time. Is there a direct way of removing the quotes (and escaping the inner quotes)?
Thank you in advance!
No it's not possible to quote or unquote with std::quote() without using a stream.
Instead, reuse a stream like the following example. It's fairly efficient.
std::ifstream file_in;
...
for (std::string line; std::getline(file_in, line); ) {
std::istringstream line_in(line);
while (...) { // tokenization loop(parse delimiters)
std::string s;
line_in >> std::quoted(s);
...
}
}
I am trying to use getline on a file (unkown size) to grap the first line, input it into a string, manipulate this string (replace words with others, move some around) and output the manipulated line back to the file.
After this, I need to do the same thing to line 2, 3, etc. until the end of the file. How would I go about doing this? I figured a while loop for getline would work, but not sure how to get the conditions for the while loop or how to manipulate each line individually. Such as lines 1 and 3 must be manipulated differently than lines 2 and 4. etc.
A rough idea of what I'm trying to do:
void readFile(string filename, string text)
{
ifstream infile;
infile.open(filename);
getline(cin, text) // pretty sure this is wrong..
infile.close(); // close here, or after manipulation???
}
void swapText(string filename, string text)
{
string decrypText;
//Manupulate several things..
return decrypText;
}
void writeToFile(string filename, string decrypText)
{
ofstream outfile;
outfile.open(filename);
outfile << decrypText << endl;
outfile.close();
}
The standard idiom for reading text lines from a file and storing them is:
std::vector<std::string> file_data;
std::string text_line;
while (std::getline(my_data_file, text_line))
{
// Optional: store the text line
file_data.push_back(text_line);
// Call a function to process (or ignore) the text line:
Process_Text_Line(text_line);
}
If you want to have a function that reads the file, you may need to pass the vector:
void Read_File(std::vector<std::string>& file_data)
{
//...
// Read the data, see "while" loop above.
}
Don't open and close the file for every read. Keep it open and read a line at a time:
std::istream in("filein.txt");
std::ostream out("fileout.txt");
std::string line;
while (std::getline(in, line)) {
// modify line as appropriate
out << line << '\n';
}
I have a text file with a series two strings delimited by a colon on each line.
I'm using getline to grab the entire line then string stream to split the two strings and put them onto a vector. The code works fine on the first pass it grabs the strings perfectly. Then after that on the 2nd pass of the while loop and so forth it doesn't grab the new input. The string stream seems to leave the original first values for some reason.
if (infile.is_open()) {
std::stringstream ss;
std::string current_line;
std::string tempProxy;
std::string tempPort;
while (std::getline(infile, current_line)) {
ss << current_line;
std::getline(ss, tempProxy, ':');
std::getline(ss, tempPort);
std::cout << tempProxy << " and " << tempPort << std::endl;
}
Any idea why it doesn't want to grab the strings from current_line on any pass except the first iteration?
You're reusing ss but not resetting it correctly. When you extract the second word from the first line, the stream is exhausted and put in an 'EOF' state. When streams are in this or any other 'error' state they don't do anything. You have to clear the error before you can continue to use them.
If you were to check for errors returned by operator<< and getline in the loop (or if you were to cause ss to throw exceptions on errors*) you would find they are indicating that they are not successful past the first iteration. It's a good general practice to always check for errors, and especially so when you're debugging.
You can clear the error by changing your loop:
while (std::getline(infile, current_line)) {
ss.clear(); // clears the error, not the contents
ss << current_line;
However doing this means that ss will accumulate all the lines in its internal buffer. The code will produce your expected output unless the file is large and you run out of memory or something like that.
You can see the accumulating internal buffer with the following:
while (std::getline(infile, current_line)) {
ss.clear();
ss << current_line;
std::cout << "ss internal buffer: " << ss.str();
Instead of using the formatted input to add ss you are probably better off using the .str() member to set it, which will replace the previous data instead of adding to it.
while (std::getline(infile, current_line)) {
ss.clear();
ss.str(current_line);
Alternatively you can construct a new stringstream in each iteration of the loop. This does ensure that no error states or data are carried over from previous iterations. It may also be slower, but you'll have to profile that for yourself.
while (std::getline(infile, current_line)) {
std::stringstream ss(current_line);
* Exceptions are nice because you don't need to remember to check them... except in cases like this where they're not enabled by default. Also I've noticed some C++ implementations have bugs in their iostreams exception code because people don't use it much.
I think you're looking for something like:
if (infile.is_open()) {
std::stringstream ss;
std::string current_line;
std::string tempProxy;
std::string tempPort;
while (std::getline(infile, current_line)) {
std::stringstream to_split;
to_split.str(current_line);
std::getline(to_split, tempProxy, ':');
std::getline(to_split, tempPort);
std::cout << tempProxy << " and " << tempPort << std::endl;
}
As my learning, I am trying to use c++ ifstream and its operator>> to read data from a text file using code below. The text file outdummy.txt has following contents:
just dummy
Hello ofstream
555
My questions is how to read char data present in the file into a char array or string. How to do this using the ifstream::operator>> in code below.
#include <iostream>
#include <fstream>
int main()
{
int a;
string s;
char buf[100];
ifstream in("outdummy.txt",ios_base::in);
in.operator>>(a); //How to read integer? How to read the string data.??
cout << a;
in.close();
getchar();
return 0;
}
If you want to use formatted input, you have to know in advance what data to expect and read it into variables of the according data type. For example, if you know that the number is always the fifth token, as in your example, you could do this:
std::string s1, s2, s3, s4;
int n;
std::ifstream in("outdummy.txt");
if (in >> s1 >> s2 >> s3 >> s4 >> n)
{
std::cout << "We read the number " << n << std::endl;
}
On the other hand, if you know that the number is always on the third line, by itself:
std::string line;
std::getline(in, line); // have line 1
std::getline(in, line); // have line 2
std::getline(in, line); // have line 3
std::istringstream iss(line);
if (iss >> n)
{
std::cout << "We read the number " << n << std::endl;
}
As you can see, to read a token as a string, you just stream it into a std::string. It's important to remember that the formatted input operator works token by token, and tokens are separated by whitespace (spaces, tabs, newlines). The usual fundamental choice to make is whether you process a file entirely in tokens (first version), or line by line (second version). For line-by-line processing, you use getline first to read one line into a string, and then use a string stream to tokenize the string.
A word about validation: You cannot know whether a formatted extraction will actually succeed, because that depends on the input data. Therefore, you should always check whether an input operation succeeded, and abort parsing if it doesn't, because in case of a failure your variables won't contain the correct data, but you have no way of knowing that later. So always say it like this:
if (in >> v) { /* ... */ } // v is some suitable variable
else { /* could not read into v */ }
if (std::getline(in, line)) { /* process line */ }
else { /* error, no line! */ }
The latter construction is usually used in a while loop, to read an entire file line by line:
while (std::getline(in, line)) { /* process line */ }
ifstream has ios_base::in by default. You don't need to specify it.
operator>> can be invoked directly as an operator: in >> a.
Reading strings is the same: in >> s, but the caveat is that it is whitespace-delimited, so it will read "just" by itself, without "dummy".
If you want to read complete lines, use std::getline(in, s).
Since you have elected to use C-strings, you can use the getline method of your ifstream object (not std::getline() which works with std::strings), which will allow you to specify the C-string and a maximum size for the buffer.
Based on what you had, and adding an additional buffer for the second line:
char buf[100];
char buf2[100];
in.getline(buf,sizeof(buf));
in.getline(buf2,sizeof(buf2));
in >> a;
However, as the other poster has proposed, try using the std::string and its methods, it will make your life easier.
You can read file contents and use a Finite State Machine for parsing.
Example:
void Parse(const char* buffer, size_t length);
size_t GetBufferSize();
size_t bufferSize = GetBufferSize();
char* buffer = new char[bufferSize];
std::ifstream in("input.txt");
while(in.getline(buffer, bufferSize)) {
Parse(buffer, in.gcount());
}
Alternatively, you can use a tool like Flex to write your parser.