【问题标题】:How do you search a document for a string in c++?如何在 C++ 中搜索文档以查找字符串?
【发布时间】:2010-04-06 03:02:19
【问题描述】:

到目前为止,这是我的代码:

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

using namespace std;

int main()
{
    int count = 0;
    string fileName;
    string keyWord;
    string word;


    cout << "Please make sure the document is in the same file as the program, thank you!" 
         << endl << "Please input document name: " ;
    getline(cin, fileName);
    cout << endl;

    cout << "Please input the word you'd like to search for: " << endl;
    cin >> keyWord;
    cout << endl;
    ifstream infile(fileName.c_str());
    while(infile.is_open())
    {
        getline(cin,word);
        if(word == keyWord)
        {
            cout << word << endl;
            count++;
        }
        if(infile.eof())
        {
            infile.close();
        }

    }
    cout << count;

}

我不知道如何进入下一个单词,目前这个无限循环......有什么建议吗?

另外...我如何告诉它打印出那个单词所在的行?

提前致谢!

【问题讨论】:

    标签: c++ fstream ifstream ofstream


    【解决方案1】:
    while(infile >> word)
    {
        if(word == keyWord)
        {
            cout << word << endl;
            count++;
        }
    }
    

    这样就可以了。请阅读更多关于流的信息。

    【讨论】:

    • 按单词而不是按行运行循环。不要投反对票,因为我不确定这是否是 OP 想要的……
    • 需要循环每个单词,但之后需要打印出单词所在的行号。
    • std::count 使用流迭代器会做同样的事情:-)
    【解决方案2】:

    如果您只想计算文件中关键字的数量,那么:

    int count = std::count(std::istream_iterator<std::string>(infile),
                           std::istream_iterator<std::string>(),
                           keyword);
    

    如果你想读单词。
    但也想打印行号然后这样的东西应该可以工作:

    std::string      line;
    std::ifstream    infile("plop");
    int              lineNumber = 0;
    
    while(std::getline(infile, line)) 
    {
        ++lineNumber ;
        std::stringstream   linestream(line);
        int hits = std::count(std::istream_iterator<std::string>(linestream),
                              std::istream_iterator<std::string>(),
                              keyword);
        if (hits != 0)
        {
            std::cout << "Line: " << lineNumber << "   Matches(" << hits << ")\n";
        } 
        count  += hits;
    } 
    

    【讨论】:

      【解决方案3】:

      问题出在这部分源码中:

      getline(cin,word);
      
      if(word == keyWord)
      {
          cout << word << endl;
          count++;
      }
      

      首先,您不想从 cin 中读取行。您想从 infile 中读取 words。因此,您应该将循环内的第一行代码替换为:

      infile >> word;
      if(word == keyWord)
          {
              cout << word << endl;
              count++;
          }
      

      另外,你应该改变循环的条件。您无需检查 infile 是否在此处打开。您应该在循环开始之前检查。对于循环,您需要检查是否已达到 eof 状态:

      if ( !infile.is_open() ) {
          cerr << "Error while opening file." << endl;
          exit( EXIT_FAILURE );
      }    
      
      while( !infile.eof() ) {
          infile >> word;
          if(word == keyWord)
          {
              cout << word << endl;
              count++;
          }
      }
      

      如您所见,现在您可以摆脱放在循环中的那个奇怪的第二个 if
      最后一步是引入“预读”技术:当我们没有阅读任何内容时,测试 eof 是没有意义的。

      if ( !infile.is_open() ) {
          cerr << "Error while opening file." << endl;
          exit( EXIT_FAILURE );
      }    
      
      infile >> word;    
      while( !infile.eof() ) {
          if( word == keyWord )
          {
              cout << word << endl;
              count++;
          }
      
          infile >> word;
      }
      

      希望这会有所帮助。

      【讨论】:

      • 您不应该像这样在循环中检查 EOF。在您尝试阅读文件末尾之前,这不是真的。因此,如果您已经阅读了整个文件 EOF 仍然是错误的,那么就进入了循环。然后 >> 运算符将无法尝试读取一个单词,并且当您输入 if 条件时,word 中的值可能未指定。循环使用:while(infile >> word) {} 只有当 >> 运算符成功从文件中读取一个单词时,才会进入循环。
      • 是的。最好在进入之前阅读,然后在循环结束之前再次阅读。术语是“预读”。但我不想在他的程序中改变这么多东西。
      • 问题在于您的示例是通过循环读取流的标准反模式。关键字出现在最后一行也是不正确的,它可能会被计算两次(取决于 >> 运算符是在测试流状态之前还是之后清除单词)。
      【解决方案4】:

      while(infile.is_open()) 更改为while(infile)。然后就可以在最后去掉多余的 eof 测试了。

      即使您遇到错误或到达文件末尾,它仍处于打开状态。您可能处于设置失败位(getline 不返回任何内容)但未遇到 eof 的情况,因此文件永远不会关闭,因此您的循环永远不会退出。使用流的operator bool 可以为您解决所有这些问题。

      【讨论】:

      • 这仍然失败,因为 EOF 仅在您尝试读取文件末尾之后才为真。使用:while(infile >> word) {}
      • @Martin York:怎么会这样?我们都在使用operator bool,所以我看不到它是如何失败的:)
      • 问题是您将在循环内执行读取。由于EOF,这可能会失败。因此,在循环内部,您将进行读取,然后进行另一个显式测试,以查看是否已达到 EOF(如果已达到),那么您将需要在任何处理完成之前退出循环。在“标准模式”中,您将读取作为 while 的一部分进行,因此如果没有更多数据,则读取会导致 EOF 变为真,因此永远不会进入循环。
      • 您必须记住,从流中的倒数第二个读取会读取 UP-TO EOF 而不会触发它。 (因此读取文件的最后一行将读取到 EOF(不触发 EOF)。因此文件中没有数据,但仍将进入循环。但第一次读取尝试使用没有数据会在循环内设置 EOF 标志。
      • @Marting York:啊,我现在明白了 :) 我仍然会使用 std::getline 但它确实需要进入循环,我同意。
      猜你喜欢
      • 1970-01-01
      • 2010-12-03
      • 2021-03-26
      • 2014-12-19
      • 1970-01-01
      • 2015-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多