Проблема с чтением файла построчно - PullRequest
1 голос
/ 26 апреля 2010

Я пытаюсь выполнить упражнение, чтобы написать программу, которая принимает следующие аргументы командной строки: входной файл, выходной файл и неопределенное количество слов. Программа должна построчно читать содержимое входного файла, находить для каждого слова, какие строки содержат это слово, и выводить строки с их номером в выходной файл. Вот мой код:

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

int main(int argc, char* argv[]) {
    if (argc < 4) {
        cerr << "Error #1: not enough arguments provided\n";
        return 1;
    }
    ifstream in(argv[1]);
    if (!in.is_open()) {
        cerr << "Error #2: input file could not be opened\n";
        return 2;
    }
    ofstream out(argv[2]);
    if (!out.is_open()) {
        cerr << "Error #3: output file could not be opened\n";
        return 3;
    }
    ostringstream oss;
    for (int i = 3; i < argc; ++i) {
        int k = 0;
        string temp;
        oss << argv[i] << ":\n\n";
        while (getline(in, temp)) {
            ++k;
            unsigned x = temp.find(argv[i]);
            if (x != string::npos)
                oss << "Line #" << k << ": " << temp << endl;
        }
    }
    string copy = oss.str();
    out << copy;
    in.close();
    out.close();
    return 0;
}

Если я попытаюсь выполнить это, я получу прогнозируемый вывод для первого заданного слова, но любые слова после него не найдены. Например, для исходного кода, приведенного выше, выдаст следующий вывод:

in:

Line #1: #include <iostream>
Line #2: #include <fstream>
Line #3: #include <string>
Line #4: #include <sstream>
Line #5: using namespace std;
Line #7: int main(int argc, char* argv[]) {
Line #12:     ifstream in(argv[1]);
Line #13:     if (!in.is_open()) {
Line #14:         cerr << "Error #2: input file could not be opened\n";
Line #22:     ostringstream oss;
Line #23:     string temp;
Line #24:     for (int i = 3; i < argc; ++i) {
Line #26:         int k = 0;
Line #28:         while (getline(in, temp)) {
Line #30:             unsigned x = temp.find(argv[i]);
Line #31:             if (x != string::npos)
Line #32:                 oss << "Line #" << k << ": " << temp << endl;
Line #35:     string copy = oss.str();
Line #37:     in.close();
out:

То есть он найдет все экземпляры первого данного слова, но не последующие. Что я тут не так делаю?

РЕДАКТИРОВАТЬ: Я пытался найти способ вернуться к началу файла, но я сдался, после того как я не смог найти метод с именем "rewind ()" или что-то подобное. Я добавил in.seekg(0, ios::beg) после цикла while, и он все еще дает мне тот же неправильный вывод.

РЕДАКТИРОВАТЬ 2: Хорошо, я, наконец, сдался и понял, что I не сможет получить желаемый исходный результат без какой-то дикой попытки использования векторов пар, поэтому я сдался и решил чтобы напечатать в этой форме:

found in at line #31:         cerr << "Error #2: input file could not be opened\n";
found out at line #34:     ofstream out(argv[2]);

То есть он печатает все строки по порядку и возглавляет каждую из них найденным конкретным словом. Вот цикл while:

ostringstream oss;
string temp;
while(getline(in,temp)) {
    static int count = 1;
    for (int i = 3; i < argc; ++i) {
        unsigned foundWord = temp.find(argv[i]);
        if (foundWord != string::npos)
            oss << "found " << argv[i] << " at line #" << count << ": " << temp << endl;
    }
    ++count;
}

В любом случае, спасибо за помощь! Само упражнение не сказало, что вывод нужно было каким-либо образом отформатировать, поэтому я считаю его полностью завершенным.

Ответы [ 6 ]

5 голосов
/ 26 апреля 2010

При i=3 файл читается в EOF во внутреннем цикле while(getline()). Поэтому на i=4,5,6… файл больше не доступен для чтения.

Вам нужно либо перемотать входной файл обратно в начало после окончания внутреннего цикла, либо изменить порядок цикла (while(getline(...)) { ... for (int i = 3; ...) { ... } ... })

3 голосов
/ 26 апреля 2010

Вы перебираете искомые строки, но у вас есть getline (), которая читает файл в цикле. Вы действительно хотите:

for each input line
   getline
    for each string we are looking for
       is string in line?
1 голос
/ 26 апреля 2010

Вы можете использовать функцию in.seekg (0, ios::beg);, чтобы перемотать начало файла перед его повторным чтением.

0 голосов
/ 26 апреля 2010

Как показывает @ Neils answer , ваш алгоритм некорректен. Его псевдокод является хорошей отправной точкой для вас. Я предлагаю вам взять его и попытаться написать каждый шаг в виде псевдокода немного более подробно. Делайте это неоднократно, пока не почувствуете, что псевдокод легко переводится в реальный код. Я считаю этот подход очень полезным, в том числе и для более сложных проблем, с которыми вы можете столкнуться позже. Саркастически говоря, подумайте, прежде чем кодировать.

Подсказка Вы должны рассмотреть вопрос о сохранении слов, которые вы ищете, в некоторой структуре данных, чтобы вы могли многократно повторять их.

0 голосов
/ 26 апреля 2010

Чтобы перемотать поток, сначала нужно вызвать in.clear(), чтобы сбросить флаги состояния потока. Только после этого вы можете позвонить in.seekg(0, ios::beg), чтобы переместить полученную позицию обратно в начало.

0 голосов
/ 26 апреля 2010

Я предполагаю, что вам нужно сбрасывать указатель файла на начало входного файла каждый раз через цикл for. Прямо сейчас вы открываете его один раз за пределами цикла и у вас нет механики, чтобы вернуть его в начало для следующих слов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...