【问题标题】:C++ Compare words between 2 different text filesC ++比较2个不同文本文件之间的单词
【发布时间】:2015-07-02 16:34:46
【问题描述】:

我有 2 个文本文件:

  1. 主文件:Library.txt
  2. 要比较的文件:fileToCompare.txt


主文件(Library.txt)包含很多单词,但仍然不完整。所以我在网上搜索找到更多的单词并将它们保存在 fileToCompare.txt 中。但是Library.txt & fileToCompare.txt中肯定有很多相同的词,所以要消除相同的词我需要比较fileToCompare.txtLibrary.txt来确定哪个词是一样的。

我消除相同单词的方法是将每个单词与 Library.txt 逐一比较。这意味着假设如果第一个单词是“apple”,那么“apple”将在 Library.txt 中逐个比较每个单词,当它找到它时,“apple”是这两个文件中出现的同一个单词。如果找不到,“apple”将在控制台中为cout 并将其保存为文本文件(之前要求用户输入文件名以保存不存在的单词)。

我发现如果 fileToCompare.txt 包含很多单词,例如1mb的文件大小,比较所有单词需要一个小时。于是我想了一个办法:

  1. fileToCompare.txt 是按字母顺序排序的,所以它总是从字母“a”开始(如果是的话)。它像往常一样比较,当它到达字母“b”时,它会在“lib/”目录中创建另一个文本文件Library2.txt
  2. ofstream所有单词从字母“b”开始到Library2.txt。现在不是与主文件比较,而是与 Library2.txt 进行比较。或者我可以说 Library2.txt 现在是主文件。
  3. 比较过程继续从字母“b”开始,如果达到字母“c”,则创建另一个文本文件Library3.txtofstream所有单词都从字母“c”开始依此类推...直到单词的结尾显然是从“z”开始,这是比较过程的结束。


但问题是它不会消除相同的词,实际上有些会,但很多不会。我检查了主文件,输出文件中的一些单词是相同的。
如果您需要,这里是 Library.txtfileToCompre.txt 的下载链接:

图书馆.txt -> https://www.dropbox.com/s/ihqpaju3b33ysgv/Library.txt?dl=0
fileToCompre.txt -> https://www.dropbox.com/s/pioy77g9mfz9och/fileToCompare.txt?dl=0

我上面解释的内容可能会令人困惑,实际上代码很混乱,我知道很难理解,一定要花一整个晚上才能弄清楚。

#include<iostream>
#include<conio.h>
#include<fstream>

using namespace std;

int main(){
    string txt="fileToCompare.txt";
    ifstream lib;
    lib2.open(txt.c_str());
    if(!lib2){
        cout<<"\n Oops! "<<txt<<" is missing!\n If such file exists, be sure to check the file extension is .txt\n";
        getch();
        main();
    }
    cout<<"\n Enter the file name to save the non-existing words\n (required an extension at the end)\n";
    getline(cin,word);
    string libPath="lib/"+word,alphaStr="a",libtxt[26]={"Library.txt","lib/Library2.txt","lib/Library3.txt","lib/Library4.txt","lib/Library5.txt","lib/Library6.txt","lib/Library7.txt","lib/Library8.txt","lib/Library9.txt","lib/Library10.txt","lib/Library11.txt","lib/Library12.txt","lib/Library13.txt","lib/Library14.txt","lib/Library15.txt","lib/Library16.txt","lib/Library17.txt","lib/Library18.txt","lib/Library19.txt","lib/Library20.txt","lib/Library21.txt","lib/Library22.txt","lib/Library23.txt","lib/Library24.txt","lib/Library25.txt","lib/Library26.txt"};
    const char* wordChar=libPath.c_str();
    const char* libManip=libtxt[0].c_str();
    int alphaI=1,boolcheck=1;
    lib.open(libManip);
    outWord.open(wordChar);
    while(getline(lib2,libStr2)){
        if(libStr2.substr(0,1)!=alphaStr){
            lib.close();
            lib.open(libManip);
            libMO.open(libtxt[alphaI].c_str());
            while(getline(lib,libStr)){
                if(libStr.substr(0,1)!=alphaStr){
                    libMO<<libStr<<endl;
                }
            }
            libManip=libtxt[alphaI].c_str();
            libMO.close();
            lib.close();
            alphaI++;
            alphaStr=libStr2.substr(0,1);
            boolcheck=1;
        }
        if(boolcheck==1){
            lib.close();
            lib.open(libManip);
            boolcheck=0;
        }
        while(getline(lib,libStr)){
            if(libStr==libStr2){
                found=1;
                break;
            }
        }
        if(!found){
            cout<<"\n "<<libStr2;
            outWord<<libStr2<<endl;
            countNF++;
        }
        count++;
        found=0;
    }
    cout<<"\n\n\n Total words: "<<count<<"\n Total words reserved: "<<countNF;
    lib2.close();
    lib.close();
    getch();
    return 0;
}

【问题讨论】:

  • 如果您的问题是关于 C++ 的,请不要标记 C,尤其是因为您有 std::string&lt;fstream&gt;&lt;iostream&gt;
  • 你的代码看起来太复杂了,不适合这个任务。
  • 您需要一个适当的数据结构,例如 std::set 或哈希映射 (std::unordered_set)。现在你有 O(MN) 时间复杂度,其中 M, N 是两个文件中的单词数。哈希映射会将其降低到 O(M+N)。

标签: c++ text-files fstream string-comparison


【解决方案1】:

您应该使用不同的算法/数据结构进行比较。 以下示例使用std::set。它读取两个文件并将合并的结果写入merged.txt

#include <iostream>
#include <set>
#include <string>
#include <fstream>

int main()
{
   std::ifstream lib("Library.txt");;

   std::set<std::string> lib_set;
   std::string word;
   while (lib >> word)
   {
      lib_set.insert(word);
   }

   std::ifstream check("fileToCompare.txt");
   while (check >> word)
   {
      lib_set.insert(word);
   }

   std::ofstream merged("merged.txt");

   std::set<std::string>::iterator it;
   for (it = lib_set.begin(); it != lib_set.end(); ++it)
   {
       merged << *it << std::endl;
   }
}

在我的计算机上为您的数据集执行此操作需要 0.8 秒。

【讨论】:

  • 这样基本上可以正常工作,但我不想合并结果,而是想计算在 fileToCompare.txt 中消除了多少单词,也许屏幕上还有 cout
【解决方案2】:

由于文件 fileToCompare.txt 和 Library.txt 是按字母顺序排序的,您的代码可以利用这一点。

  1. 从每个文件中读取一个单词。
  2. 如果两个单词相同,则从文件中读取下一个单词。
  3. 如果 fileToCompare.txt 中的单词小于 Library.txt 中的单词,请保留 Library.txt 中的单词并读取 fileToCompare.txt 中的下一个单词。否则,保留 fileToCompare.txt 中的单词并阅读 Library.txt 中的下一个单词。
  4. 继续这样做,直到没有更多单词要阅读。
  5. 最后,如果fileToCompare.txt中还有剩余的字,请阅读并打印出来。

以下程序遵循上述逻辑,似乎对我有用。

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

void compareFiles(ifstream& txtf, ifstream& libf)
{
   string txtWord;
   string libWord;
   bool readTxt = true;
   bool readLib = true;

   while ( true )
   {
      if ( readLib )
      {
         // Try to read the next word from the libf
         // If the read is not successful, break out of the loop.
         if ( ! (libf >> libWord) )
         {
            break;
         }
      }

      if ( readTxt )
      {
         // Try to read the next word from the txtf
         // If the read is not successful, break out of the loop.
         if ( ! (txtf >> txtWord) )
         {
            break;
         }
      }

      if ( txtWord == libWord )
      {
         // The same word exists in both files.
         // Read the next words from both files.
         readTxt = readLib = true;
         continue;
      }

      // A word from the text file doesn't exist in the library file.
      // Print the word from the text file if the word from the text file
      // was read in this iteration.
      if ( readTxt )
      {
         cout << txtWord << endl;
      }

      // The next word we read will depend on whether the txtWord is less
      // or greater than libWord.
      if ( txtWord < libWord )
      {
         // Read the next txtWord but keep the current libWord.
         readTxt = true;
         readLib = false;
      }
      else
      {
         // Read the next libWord but keep the current txtWord.
         readTxt = false;
         readLib = true;
      }

      // The above logic can be shortened to.
      // readTxt = (textWord < libWord);
      // readLib = !readTxt;
   }

   // When the previous while loop ends, there might be more words in txtf.
   // Read the remaining words from txtf and print them.
   while ( txtf >> txtWord )
   {
      cout << txtWord << endl;
   }
}

void compareFiles(string const& txt, string const& lib)
{
   ifstream txtf(txt);
   ifstream libf(lib);
   compareFiles(txtf, libf);
}

int main()
{
   string txt="fileToCompare.txt";
   string lib="Library.txt";

   compareFiles(txt, lib);

   return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多