c++ - 除非复制并粘贴文本,否则在C++程序中输入的文本文件将无法工作

标签 c++ text markov-chains markov

我的代码中有一个非常奇怪的错误,很难解释。让我从程序的工作开始:基本上,C++程序(从同一目录中名为“input.txt”的文件)获取输入文本,并使用马尔可夫链生成一些类似于输入文本样式的人工输出文本并将其打印到终端。

当我直接将“爱丽丝梦游仙境”(Alice in Wonderland)(http://paulo-jorente.de/text/alice_oz.txt)的文本复制并粘贴到“input.txt”中时,它会起作用,但是如果我在文本文件内容的开头或结尾添加任何单词或字符,则代码停止运行(或无限运行)。但是,如果我在文本文件内容中间的任意位置添加文本,则不会发生这种情况。

如果您要自己进行测试,请尝试运行代码并将Alice in Wonderland复制到“input.txt”中。然后,在成功运行之后,转到input.txt,并在“Alice”(“...再次回家!”)的文本末尾键入一些随机字符或单词,然后尝试再次运行;它会失败。

这是代码:

#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;
}


这是一个非常奇怪的错误,非常感谢您提供的任何帮助!谢谢!

最佳答案

关于std::mapoperator[]()的时间复杂性,可能需要考虑一下。

Using operator[] : “[]” can also be used to insert elements in map. Similar to above functions and returns the pointer to the newly constructed element. Difference is that this operator always constructs a new element i.e even if a value is not mapped to key, default constructor is called and assigns a “null” or “empty” value to the key. Size of map is always increased by 1. Time complexity : log(n) where n is size of map


courtesy from: geeksforgeeks



在类的createDictionary()函数中,尝试在第二个while循环中添加以下代码行:
{
    //...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条目。运行和完成大约需要20到30秒。

当我在文件末尾添加文本“再见!”时,将其保存并运行程序/调试器,它生成了62039个条目。再次花费了大约20-30秒来运行。

然后,将文本“Hello World”添加到文件的开头,保存并运行程序/调试器,并生成62041条目。再次花费了大约20-30秒来运行。

但是,在此过程中有几次,它在您的 map 中生成了很多条目,但是代码仍在循环中……一次大约是620xx-640xx。我不知道是什么原因导致它生成了如此多的键...但是就像我说的那样,它有几次退出打印值,但是仍然在相同的while循环中进行迭代,但是它的大小 map 没有增加...

这是我第一次尝试在文件末尾输入附加文本后,在文件开头输入文本的情况。这是当我决定打印出 map 的大小并注意到我正在遇到无限循环时...然后,我停止了调试器,返回到文本文件,并将插入的文本保留在开头,但删除了附加的文本最后,请确保在文本末尾留一个空格。

这次我运行程序/调试器时,它可以正常工作,并生成了62039个条目。再次花费了大约20-30秒来运行。之后,第一次成功运行并在开头添加了文本,这是我在末尾添加文本时运行的很好。然后,我什至试图拥有“Hello World!”然后使用Enter键进入换行符,然后在文本文件中输入“再见!”前面也有一个,它仍然可以正常工作。

是的,有些原因导致了错误,但是我不知道是什么原因导致了该错误。但是,我相信我已将其追溯到这个while循环和要退出的条件分支中……它应该已经脱离了这个循环,进入了createText函数,但是它从未爆发过,您必须满足以下条件:
if (next == std::string::npos) return


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

不知何故没有得到满足。

时间复杂度还可以,但这不是最好的,但也不是最坏的,因为在O(log n)时间内大约有62-63k个条目在运行。这也不包括计算需要考虑的空间复杂性。

可能是在一次运行期间,您可能会导致堆栈溢出,从而导致无限循环,而在下次运行时,则可能不会。我认为这与直接在文本文件中添加文本没有任何关系,除了它会增加O(log N) time中 map 的大小并增加空间复杂度之外。

无论将什么添加到此文本文件中,以及保存后,编写程序或算法的方式如何,它都会通过迭代器类按char类型将该文件的所有内容作为指针索引拉出,并将其存储到单个字符串中,fileText。构造完此字符串后,您的类的成员字符串中大约包含336940个字符。

希望这些信息可以指导您缩小程序中错误的位置,并确定导致错误的真正原因。确实很难缩小这个罪魁祸首。

关于c++ - 除非复制并粘贴文本,否则在C++程序中输入的文本文件将无法工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60425063/

相关文章:

c++ - MAC OS Eclipse C++ 启动二进制文件失败

c++ - adafruit 示例中的奇怪类实例化

c++ - 默认复制移动构造函数效率不同

c++ - float 和 double (C++) 的实际最小/最大值是多少

algorithm - 文本打包算法

python - 有效地从 numpy 数组中采样以相同数字结尾的连续整数序列?

html - 在 CSS 中设置最大字符长度

ios - 如何使用 Core Graphics 右对齐文本

python - 找到具有左特征值的马尔可夫稳态(使用 numpy 或 scipy)

matlab - 遍历马尔可夫链平稳分布 : solving eqns