'How do I find the line number and line item number in a text file?
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;
}
Solution 1:[1]
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) % 4will 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
jas 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
nto wrap around inside the buffer:(i - 1 + j) % n. - If
i - 1 + jwas a negative value then(i - 1 + j) % nbecomes a negativ value as well. To fix this,nis 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.)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
