I need to find the line number and position number in the line with the specified character in the text file. I did this, but found the last symbol. I have a task to find the fourth point "." from the end of the text file, how is this possible?
Text file:
One One
Two
....
Three
..
Three
Now I get the following result:
Line: 2
Pos: 6
What I have tried:
Check out my code (I'm looking for the first dot from the end of the file):
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
ifstream fin("t.txt");
string line;
int lines = 0;
int characters = 0;
int found_line = 0;
size_t found_pos = string::npos;
while (true)
{
if (!getline(fin, line)) break;
auto pos = line.find_last_of('.');
if (pos != string::npos)
{
found_line = lines;
found_pos = (characters pos);
}
lines;
characters = line.length();
}
if (found_pos != string::npos)
{
found_line = (lines - 0 - found_line); // line no, counting backwards from the bottom of the file
found_pos = (characters - 0 - found_pos); // pos of the 'first' dot, counting backwards from the end of the file
cout << "line " << found_line << "\n";
cout << "pos " << found_pos << "\n" 1;
}
return 0;
}
CodePudding user response:
In my comment, I sketched the following possible algorithm to solve OPs issue:
What you could do: While reading the file you can count the line numbers. Scan the line for one (or multiple)
.
s. The results can be stored in an array of 4 entries. (You have to manage an index for this.) For each found.
, you store the line and inc. the index modulo 4 (e.g.i = (i 1) % 4;
. When you reached the end of file, the(i 1) % 4
will contain the line for the 4th . from end. Of course, you also have to count that you found at least 4.
s (to handle edge cases).
Just for fun, I made an MCVE on coliru:
#include <array>
#include <fstream>
#include <iostream>
#include <string>
// (a kind of) ring buffer
template <typename V, int N>
struct RingT {
std::array<V, N> values;
int i = 0;
int n = 0;
void push(const V& value)
{
values[i ] = value;
if (i >= N) i = 0;
if (n < N) n;
}
int size() const { return n; }
const V& operator[](int j) const { return values[((i - 1 j) % n n) % n]; }
};
// text coordinates
struct Coord {
int line, col;
};
int main()
{
const int N = 4; // the number of occurrences (from end) to count
const char C = '.'; // the character to count occurrences for
// use (a kind of) ring buffer to store text coordinates
RingT<Coord, N> coords;
// scan file for occurrences of character C
#if 0 // OP
std::ifstream fIn("t.txt");
#else // for online check
std::ifstream fIn("main.cpp");
#endif // 0
int line = 1;
for (std::string buffer; std::getline(fIn, buffer); line) {
for (size_t col = 0;; col) {
col = buffer.find(C, col);
if (col < buffer.size()) coords.push({ line, (int)col });
else break;
}
}
// output result
if (coords.size() < N) {
std::cerr << "ERROR! File didn't contain " << N << " occurrences of '" << C << "'.\n";
} else {
const Coord& coord = coords[1]; // equivalent to coords[N - 1] -> it's a ring
std::cout << "The " << N << "th occurrence of '" << C << "' from end"
<< " was in line " << coord.line << ", col. " << coord.col << '\n';
}
}
Output:
The 4th occurrence of '.' from end was in line 52, col. 85
To simplify things on coliru, I used the source code main.cpp
instead of t.txt
. The online viewer of coliru displays line numbers. Hence, it's quite easy to check that the 4th occurrence of .
from end is in fact in line 52. Line 52 is this one:
std::cerr << "ERROR! File didn't contain " << N << " occurrences of '" << C << "'.\n";
(I must admit that I didn't check the column but 85 looks reasonable.—There is a .
near the end of line.)
The complete code is actually quite simple and straight-forward. The most convoluted thing is probably the RingT::operator[]
:
const V& operator[](int j) const { return values[((i - 1 j) % n n) % n]; }
Thus, I'd like to dissect and explain it a bit:
- There is given the index
j
as argument which should be looked up. - The index is relative to the last entry which was done:
i - 1 j
. - The index is used modulo
n
to wrap around inside the buffer:(i - 1 j) % n
. - If
i - 1 j
was a negative value then(i - 1 j) % n
becomes a negativ value as well. To fix this,n
is added and then again modulon
:((i - 1 j) % n n) % n
.
This grants that the resulting index for array access will always be in the range [0, n). (Admittedly, possible integer overflow issues are ignored.)