Текстовый файл как ввод в программе C ++ не будет работать, если текст не будет скопирован и вставлен - PullRequest
1 голос
/ 27 февраля 2020

У меня есть очень странная ошибка в моем коде, которую немного сложно объяснить. Позвольте мне начать с того, что делает программа: в основном, программа C ++ берет входной текст (из файла с именем "input.txt" в той же директории) и использует цепочки Маркова для генерации некоторого искусственного выходного текста, который напоминает стиль входного текста и распечатывает его в терминал.

Работает, когда я копирую и вставляю текст «Алисы в стране чудес» (http://paulo-jorente.de/text/alice_oz.txt) прямо в «input.txt», но если я добавляю какие-либо слова или символы в начало или конец содержимого текстового файла, затем код останавливается (или работает бесконечно). Однако этого не произойдет, если я добавлю текст где-нибудь посередине содержимого текстового файла.

Если вы хотите проверить это самостоятельно, попробуйте запустить код с Алисой в Стране Чудес, скопированной в «input.txt». Затем, после успешного запуска, go введите input.txt и введите несколько случайных символов или слов после последнего текста из «Алисы» («... снова домой!») И попробуйте запустить его снова; это не удастся.

Вот код:

#include <ctime>
#include <iostream>
#include <algorithm>
#include <fstream>
#include <string>
#include <vector>
#include <map>
using namespace std;

class markovTweet{
    string fileText;
    map<string, vector<string> > dictionary;

public:

    void create(unsigned int keyLength, unsigned int words) {
        ifstream f("input.txt");
        if(f.good()){
          fileText.assign((istreambuf_iterator<char>(f)), istreambuf_iterator<char>());
        }else{
          cout << "File cannot be read. Ensure there is a file called input.txt in this directory." << "\n" << endl;
          return;
        }
        if(fileText.length() < 1){
          return;
        }
        cout << "\n" << "file imported" << "\n";
        createDictionary(keyLength);
        cout << "\n" << "createDictionary" << "\n" << "\n";
        createText(words - keyLength);
        cout << "\n" << "text created, done" << endl;
    }

private:

    void createText(int w) {
        string key, first, second;
        size_t next;
        map<string, vector<string> >::iterator it = dictionary.begin();
        advance( it, rand() % dictionary.size() );
        key = (*it).first;
        cout << key;
        while(true) {
            vector<string> d = dictionary[key];
            if(d.size() < 1) break;
            second = d[rand() % d.size()];
            if(second.length() < 1) break;
            cout << " " << second;
            if(--w < 0) break;
            next = key.find_first_of( 32, 0 );
            first = key.substr( next + 1 );
            key = first + " " + second;
        }
        cout << "\n";
    }

    void createDictionary(unsigned int kl) {
        string w1, key;
        size_t wc = 0, pos, next;
        next = fileText.find_first_not_of( 32, 0 );
        if(next == string::npos) return;
        while(wc < kl) {
            pos = fileText.find_first_of(' ', next);
            w1 = fileText.substr(next, pos - next);
            key += w1 + " ";
            next = fileText.find_first_not_of(32, pos + 1);
            if(next == string::npos) return;
            wc++;
        }
        key = key.substr(0, key.size() - 1);
        while(true) {
            next = fileText.find_first_not_of(32, pos + 1);
            if(next == string::npos) return;
            pos = fileText.find_first_of(32, next);
            w1 = fileText.substr(next, pos - next);
            if(w1.size() < 1) break;
            if(find( dictionary[key].begin(), dictionary[key].end(), w1) == dictionary[key].end() ) 
                dictionary[key].push_back(w1);
            key = key.substr(key.find_first_of(32) + 1) + " " + w1;
        }
    }
};

int main() {  
    markovTweet t;
    cout << "\n" << "Artificially generated tweet using Markov Chains based off of input.txt: " << "\n" << "\n";
    //lower first number is more random sounding text, second number is how long output is.
    t.create(4, 30);
    return 0;
}

Это очень странная ошибка, и любая помощь, которую вы можете предложить, высоко ценится! Спасибо!

1 Ответ

0 голосов
/ 27 февраля 2020

Возможно, стоит подумать о сложности времени std::map для его operator[]().

Использование оператора []: «[]» также можно использовать для вставки элементов в карта. Аналогичен приведенным выше функциям и возвращает указатель на вновь созданный элемент. Разница в том, что этот оператор всегда создает новый элемент, т. Е. Даже если значение не сопоставлено с ключом, вызывается конструктор по умолчанию, который присваивает ключу «нулевое» или «пустое» значение. Размер карты всегда увеличивается на 1. Сложность времени: log (n), где n - размер карты


Предоставлено:
geeksforgeeks



В функции createDictionary() вашего класса попробуйте добавить эту строку кода в 2 nd , а l oop:

{
    //...code 
    if (find(dictionary[key].begin(), dictionary[key].end(), w1) == dictionary[key].end()) {
          dictionary[key].push_back(w1);
          std::cout << dictionary.size() << std::endl;
    //code...
}

Когда я скопировал текст из файл, который он генерировал 62037 записей в вашем словаре или hashmap. Запуск занимает около 20 - 30 секунд и заканчивается sh.

Когда я добавил текст «До свидания!» В конец файла, сохранил его и запустил программу / отладчик, он сгенерировал 62039 записей. Снова потребовалось около 20-30 секунд для запуска.

Затем я добавил текст «Hello World» в начало файла, сохранил его, запустил программу / отладчик и сгенерировал 62041 записей. Снова потребовалось около 20-30 секунд для запуска.

Однако во время этого процесса было несколько раз, когда он генерировал столько записей на вашей карте, но код все еще проходил через l * 1060. * ... Один раз это было около 620xx - 640xx. Я не знаю, что послужило причиной того, что это сгенерировало такое количество ключей ... но, как я уже сказал, пару раз он прекращал печатать значения, но продолжал повторять то же самое, пока l oop, но размер карты не увеличивался ...

Это произошло в первый раз, когда я вводил текст в начале файла после того, как попробовал его с добавленным текстом в конце. Именно тогда я решил распечатать размер вашей карты и заметил, что получаю это бесконечное значение l oop ... Затем я остановил отладчик, вернулся к текстовому файлу и сохранил вставленный текст в начале, но удалил добавленный текст в конце, обеспечивающий пробел в конце текста.

На этот раз, когда я запустил программу / отладчик, он работал правильно и сгенерировал 62039 записей. Снова потребовалось около 20-30 секунд, чтобы бежать. После первого успешного запуска со вставленным текстом в начале, когда я добавил текст в конце, он заработал нормально. Я тогда даже пытался иметь "Hello World!" сопровождаемый новой строкой, используя ввод в текстовый файл и имея "До свидания!" перед ним также стоит один, и он все еще работает нормально.


Да, есть что-то, что вызывает ошибку, но я не знаю точно, что вызывает это. Тем не менее, я считаю, что я проследил, чтобы он находился в пределах этого while l oop и условного ветвления для выхода ... Он должен был выйти из этого l oop и войти в функцию createText, но это никогда не возникало, условие, для которого вы:

if (next == std::string::npos) return

и

if (w1.size() < 1) break;

так или иначе не выполнялись.


Временная сложность в порядке, однако она не самая лучшая, но и не самая плохая, поскольку в O(log n) времени выполняется приблизительно 62-63 тыс. Записей. Это также не включает в себя подсчет сложности пространства, которую нужно принимать во внимание.


Возможно, во время одного запуска вы получите переполнение стека, которое вызывает бесконечное l oop, и в следующий раз, когда вы его запустите, это может не произойти. Я не думаю, что это связано с непосредственным добавлением текста в текстовый файл, за исключением того, что это увеличит размер вашей карты в O(log N) time и также увеличит сложность пространства.

Независимо от того, что вы добавляете в этот текстовый файл и после его сохранения, способа написания вашей программы или алгоритмов, он извлекает все содержимое этого файла в виде индексов-указателей по типу char через классы итераторов и сохраняет его в одна строка, fileText. После того, как эта строка создана, в строке члена вашего класса будет приблизительно 336940 символов.


Надеемся, что эта информация поможет вам сузить местонахождение ошибки в вашей программе и определить, что на самом деле ее вызывает. Трудно сузить этого преступника.

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