I used this code to read lines from file, but I noticed, that it didn't read line breaks:
ifstream fs8(sourceFile);
string line;
while (getline(fs8, line))
{
//here I am doing convertation from utf8 to utf16, but I need also to convert symbol "\n"
}
How to read line with line breaks ?
std::getline() reads data up to a delimiter, which is not stored. By default, that delimiter is '\n'. So you would have to either:
a) Pick a different delimiter -- but then you would no longer read "lines".
b) Add the newline to the data read (line += '\n').
I'd go for b), if you really need that newline converted. (I don't quite see why that would be necessary, but who am I to judge. ;-) )
Related
I am reading a file of 5 doubles in a line through a for loop and storing them into a vector of structs and sometimes there is less then 5 doubles on the line. The file looks something like
111.111 222.222 333.333 444.444 555.555
666.666
777.777 (whitespace) 888.888 999.999
struct temp_struct{
double d1,d2,d3,d4,d5
};
vector<temp_struct> data;
for(int i=0;i<3;i++)
File>>data.at(i).d1>>data.at(i).d2>>data.at(i).d3>>data.at(i).d4>>data.at(i).d5;
Is there a way to test for the empty space after 666.666 and inbetween 777.777 and 888.888.
Because right now the way I am reading it in, after 666.666 it will go to the next line of the file and read 777.777 and 888.888 999.999 so that the struct looks like
data.at(1).d1=666.666 data.at(1).d2=777.777 data.at(1).d3=888.888 and data.at(1).d4=999.999 where I would rather have
data.at(1).d1=666.666, break because of end of line
data.at(2).d1=777.777, data.at(2).d2=0, data.at(3).d3=888.8888
I am programming in VS2010 C++
The usual way to parse line-based text is to use std::getline() in combination with an std::istringstream, e.g.:
for (std::string line; std::getline(in, line); ) {
std::istringstream lin(line);
// parse the line using `line`
}
There are other approaches, too, though. For example, it is possible to set up a stream to not consider a newline whitespace: this way, trying to read numbers when a newline is encountered the attempt to read the value would fail! The way to change what is considered whitespace is to install a custom std::locale object with a custom version of std::ctype<char>.
I have function like this (I found it somewhere, it works with \t separator).
vector<string> delimited_str_to_vector(string& str, string delimiter)
{
vector<string> retVect;
size_t pos = 0;
while(str.substr(pos).find(delimiter) != string::npos)
{
retVect.push_back(str.substr(pos, str.substr(pos).find(delimiter)));
pos += str.substr(pos).find(delimiter) + delimiter.size();
}
retVect.push_back(str.substr(pos));
return retVect;
}
I have problem with splitting string by "\r\n" delimiter. What am I doing wrong?
string data = get_file_contents("csvfile.txt");
vector<string> csvRows = delimited_str_to_vector(data, "\r\n");
I'm sure, that my file uses CRLF for new line.
You can use getline to read the file line by line, which:
Extracts characters from is and stores them into str until the delimitation character delim is found (or the newline character, '\n' ...) If the delimiter is found, it is extracted and discarded, i.e. it is not stored and the next input operation will begin after it.
Perhaps you are already reading the file through a function that removes line endings.
If you open your file in text mode, i.e., you don't mention std::ios_base::binary (or one of it alternate spellings) it is likely that the system specific end of line sequences is replaced by \n characters. That is, even if your source file used \r\n, you may not see this character sequence when reading the file. Add the binary flag when opening the file if you really want to process these sequences.
I have a file for example
M
4
2
//comments
.#..
It is given to the program via stdin. I can't use fstream, just iostream.
If I want to read the whole thing character by character could I do?
char first_letter, first_num, second_num;
cin >> first_letter;
cin >> first_num;
cin >> second_num;
Or would the end of the line mess up cin? As in, does cin know after it reads M for first_letter, that it needs to go to the end line?
Secondly I dont want to read the comment lines. My plan is that if I see a / I will use getline to "trash" the line then move to the . # . . and store those in my array. Would that be the best way to do that?
Firstly, streams skip whitespace (space, tabs, newlines) by default, so that part is easy.
Now, concerning the comment lines, this is a bit more complicated. You can use std::getline() to read one line. This will store the line in a string and discard the trailing newline. However, if you e.g. read the first letter in your code above, the newline remains in the stream, so getline() will read an empty string. In short, don't mix line-based and token-based input.
In practice, you read a line and either parse the it manually or you create a stream for that:
while(getline(in, line)) {
if(line.empty()) continue; // empty line
if(line[0] == '#') continue; // comment line
// parse line
std::stringstream s(line);
char c;
s >> c;
}
string numbers;
string fileName = "text.txt";
ifstream inputFile;
inputFile.open(fileName.c_str(),ios_base::in);
inputFile >> numbers;
inputFile.close();
cout << numbers;
And my text.txt file is:
1 2 3 4 5
basically a set of integers separated by tabs.
The problem is the program only reads the first integer in the text.txt file and ignores the rest for some reason. If I remove the tabs between the integers it works fine, but with tabs between them, it won't work. What causes this? As far as I know it should ignore any white space characters or am I mistaken? If so is there a better way to get each of these numbers from the text file?
When reading formatted strings the input operator starts with ignoring leading whitespace. Then it reads non-whitespace characters up to the first space and stops. The non-whitespace characters get stored in the std::string. If there are only whitespace characters before the stream reaches end of file (or some error for that matter), reading fails. Thus, your program reads one "word" (in this case a number) and stops reading.
Unfortunately, you only said what you are doing and what the problems are with your approach (where you problem description failed to cover the case where reading the input fails in the first place). Here are a few things you might want to try:
If you want to read multiple words, you can do so, e.g., by reading all words:
std::vector<std::string> words;
std::copy(std::istream_iterator<std::string>(inputFile),
std::istream_iterator<std::string>(),
std::back_inserter(words));
This will read all words from inputFile and store them as a sequence of std::strings in the vector words. Since you file contains numbers you might want to replace std::string by int to read numbers in a readily accessible form.
If you want to read a line rather than a word you can use std::getline() instead:
if (std::getline(inputFile, line)) { ... }
If you want to read multiple lines, you'd put this operation into a loop: There is, unfortunately, no read-made approach to read a sequence of lines as there is for words.
If you want to read the entire file, not just the first line, into a file, you can also use std::getline() but you'd need to know about one character value which doesn't occur in your file, e.g., the null value:
if (std::getline(inputFile, text, char()) { ... }
This approach considers a "line" a sequence of characters up to a null character. You can use any other character value as well. If you can't be sure about the character values, you can read an entire file using std::string's constructor taking iterators:
std::string text((std::istreambuf_iterator<char>(inputFile)),
std::istreambuf_iterator<char>());
Note, that the extra pair of parenthesis around the first parameter is, unfortunately, necessary (if you are using C++ 2011 you can avoid them by using braces, instead of parenthesis).
Use getline to do the reading.
string numbers;
if (inputFile.is_open())//checking if open
{
getline (inputFile,numbers); //fetches entire line into string numbers
inputFile.close();
}
Your program does behave exactly as in your description : inputFile >> numbers; just extract the first integer in the input file, so if you suppress the tab, inputFile>> will extract the number 12345, not 5 five numbers [1,2,3,4,5].
a better method :
vector< int > numbers;
string fileName = "text.txt";
ifstream inputFile;
inputFile.open(fileName.c_str(),ios_base::in);
char c;
while (inputFile.good()) // loop while extraction from file is possible
{
c = inputFile.get(); // get character from file
if ( inputFile.good() and c!= '\t' and c!=' ' ) // not sure of tab and space encoding in C++
{
numbers.push_back( (int) c);
}
}
inputFile.close();
once again I ask for help. I haven't coded anything for sometime!
Now I have a text file filled with random gibberish. I already have a basic idea on how I will count the number of occurrences per word.
What really stumps me is how I will determine what line the word is in. Gut instinct tells me to look for the newline character at the end of each line. However I have to do this while going through the text file the first time right? Since if I do it afterwords it will do no good.
I already am getting the words via the following code:
vector<string> words;
string currentWord;
while(!inputFile.eof())
{
inputFile >> currentWord;
words.push_back(currentWord);
}
This is for a text file with no set structure. Using the above code gives me a nice little(big) vector of words, but it doesn't give me the line they occur in.
Would I have to get the entire line, then process it into words to make this possible?
Use a std::map<std::string, int> to count the word occurrences -- the int is the number of times it exists.
If you need like by line input, use std::getline(std::istream&, std::string&), like this:
std::vector<std::string> lines;
std::ifstream file(...) //Fill in accordingly.
std::string currentLine;
while(std::getline(file, currentLine))
lines.push_back(currentLine);
You can split a line apart by putting it into an std::istringstream first and then using operator>>. (Alternately, you could cobble up some sort of splitter using std::find and other algorithmic primitaves)
EDIT: This is the same thing as in #dash-tom-bang's answer, but modified to be correct with respect to error handing:
vector<string> words;
int currentLine = 1; // or 0, however you wish to count...
string line;
while (getline(inputFile, line))
{
istringstream inputString(line);
string word;
while (inputString >> word)
words.push_back(pair(word, currentLine));
}
Short and sweet.
vector< map< string, size_t > > line_word_counts;
string line, word;
while ( getline( cin, line ) ) {
line_word_counts.push_back();
map< string, size_t > &word_counts = line_word_counts.back();
istringstream line_is( line );
while ( is >> word ) ++ word_counts[ word ];
}
cout << "'Hello' appears on line 5 " << line_word_counts[5-1]["Hello"]
<< " times\n";
You're going to have to abandon reading into strings, because operator >>(istream&, string&) discards white space and the contents of the white space (== '\n' or != '\n', that is the question...) is what will give you line numbers.
This is where OOP can save the day. You need to write a class to act as a "front end" for reading from the file. Its job will be to buffer data from the file, and return words one at a time to the caller.
Internally, the class needs to read data from the file a block (say, 4096 bytes) at a time. Then a string GetWord() (yes, returning by value here is good) method will:
First, read any white space characters, taking care to increment the object's lineNumber member every time it hits a \n.
Then read non-whitespace characters, putting them into the string object you'll be returning.
If it runs out of stuff to read, read the next block and continue.
If the you hit the end of file, the string you have is the whole word (which may be empty) and should be returned.
If the function returns an empty string, that tells the caller that the end of file has been reached. (Files usually end with whitespace characters, so reading whitespace characters cannot imply that there will be a word later on.)
Then you can call this method at the same place in your code as your cin >> line and the rest of the code doesn't need to know the details of your block buffering.
An alternative approach is to read things a line at a time, but all the read functions that would work for you require you to create a fixed-size buffer to read into beforehand, and if the line is longer than that buffer, you have to deal with it somehow. It could get more complicated than the class I described.