【问题标题】:What is the most efficient way to split a line of a text in C++?在 C++ 中分割一行文本的最有效方法是什么?
【发布时间】:2014-09-10 09:51:15
【问题描述】:

我正在处理一些文本文件,我需要阅读其中的所有行,并且需要访问这些行中的字符串。我使用了如下方法(假设每行有 4 个字符串):

string word1 , word2, word3, line;
while( getline( inputFile,line )){

    stringstream row(line);
    row>>word1>>word2>>word3>>word4;

}

但是,结果非常低效,我的程序运行得不是很快。我该如何改进方法?提前致谢!

【问题讨论】:

  • 那里有一堆解决方案:stackoverflow.com/questions/1120140/…
  • 不要用getline/stringstream读取行,直接使用istream
  • “但是,结果非常低效”——当我质疑时不要生气。每行有四个“字符串”和一个缓冲流,代码将接近 epsilon 以提高速度。我有一个 100 万行的 txt 文件,每行包含四个随机字符串,长度从 5 到 30 个字符不等,上面的代码将在大约 3 秒内枚举整个内容(在使用 3 年的 macbook air 笔记本电脑上,不少)。您的问题可能与您共享的数据有关,或者不在此代码中。发布的代码的发布版本应该翻阅文件。
  • 这段代码只是一个例子,这就是为什么我说“假设每行有 4 个字符串”。另外,这不是整个程序。正如标题所总结的,我想学习在 .txt 行中读取字符串的最有效方法。因此我只写了执行读取操作的部分
  • 我怀疑这不是整个程序,这在某种程度上是我的观点。 没有下面的答案(仍然,无论如何)做那些发布的代码行所做的事情。 (禁止换行、平台换行处理等)。你能根据复杂的strtok() + memcpy() 算法编写一百行代码来绕过行缓冲区和字缓冲区的分配和复制吗?当然。最后值得吗?问唐纳德·高德纳。那就是see this。 Mats 对复杂性和性能之间的权衡进行了精彩的剖析。

标签: c++ file-io inputstream stringstream


【解决方案1】:

不要使用 getline 和字符串流 使用读取函数读取大块/块数据中的所有字符串

ifstream file ("file.txt", ios::in|ios::binary|ios::ate);
if (file.is_open())
{
    file.seekg(0, ios::end);
    int block_size = file.tellg();
    char *contents = new char [block_size];
    file.seekg (0, ios::beg);
    file.read (contents, block_size);
    file.close();

    //... now deal with the string (I/O operations take more time once the entire 
    // file is in RAM it will be faster to operate on )

    delete [] contents;
}

如果您的文件大小超过堆内存的限制,您将必须读取预定义的块大小并对其进行操作并释放内存并移至下一个块

Suggestion

【讨论】:

    【解决方案2】:

    我看到了两种变体。 我比较了此类文件中的所有三个变体(您的和 2 个地雷):

    (bash)for ((i=0;i test.txt

    test.txt 放在 tmpfs 中。 所有时间都以秒为单位。

    您的变体: CPU时间0.130000,abs时间0.135514

    我的变体 1: CPU时间0.060000,绝对时间0.062909,

    我的变体 2: CPU时间0.050000,abs时间0.052963

    1)“C模式”:

    //FILE *in  
    char buf[1000];
    buf[sizeof(buf) - 1] = '\0';
    char w1[sizeof(buf)];
    char w2[sizeof(buf)];
    char w3[sizeof(buf)];
    char w4[sizeof(buf)];
    while (fgets(buf, sizeof(buf) - 1, in) != nullptr) {
        *w1 = *w2 = *w3 = *w4 = '\0';
        sscanf(buf, "%s %s %s %s", w1, w2, w3, w4);//here should be check for == 4
        //words.emplace_back(std::string(w1), std::string(w2), std::string(w3), std::string(w4));
    }
    

    2)“映射文件”:

    //MapFile in;
    const char *beg = in.begin();
    const char *end = beg + file_size;
    std::string w[4];
    const char *ptr = beg;
    bool eof = false;
    do {
        for (int i = 0; i < 4; ++i) {
            const char *q = find_end_of_word(ptr, end);
            w[i].assign(ptr, q - ptr);
            if (q == end) {
                eof = true;
                break;
            }
            ptr = q;
            while (ptr != end && (*ptr == ' ' || *ptr == '\t' || *ptr == '\n'))
                ++ptr;
            if (ptr == end) {
                eof = true;
                break;
            }
        }
        //words.emplace_back(w[0], w[1], w[2], w[3]);
    

    // printf("%s %s %s %s\n", w[0].c_str(), w[1].c_str(), w[2].c_str(), w[3 ].c_str()); } 而 (!eof);

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-25
      • 1970-01-01
      • 1970-01-01
      • 2016-09-05
      • 1970-01-01
      相关资源
      最近更新 更多