如何将文本文件分割成单词?

8
我正在处理一个任务,需要读取文件并统计其中的行数和单词数。我尝试使用getline和strtok结合while循环的方法,但没有成功。
文件名:example.txt(待读取的文件)。
引用: “嗨,你好,真是个惊喜。 欢迎来到这里。 祝你在这里过得愉快。 (3行,若干单词)。”
Readfile.cpp
#include <iostream>
#include <fstream>
#include<string>
using namespace std;
int main()
{
  ifstream in("example.txt");
  int count = 0;

  if(!in)
  {
    cout << "Cannot open input file.\n";
    return 1;
  }

  char str[255];
  string tok;
  char * t2;

  while(in)
  {
    in.getline(str, 255);
    in>>tok;
    char *dup = strdup(tok.c_str());
    do 
    {
        t2 = strtok(dup," ");
    }while(t2 != NULL);
    cout<<t2<<endl;
    free (dup);
    count++;
  }
  in.close();
  cout<<count;
  return 0;
}

你需要说得更详细一些,而不仅仅是“没有起作用”。告诉我们你遇到了什么错误,或者你的程序与你预期的有何不同之处,然后提出具体的问题。我们不会为你调试或重写作业。 - Blorgbeard
17
以下是一些示例,您可以参考:http://www.codeproject.com/KB/recipes/Tokenizer.aspx 它们非常高效且优雅。String Toolkit Library使得C++中的复杂字符串处理变得简单易行。 - Matthieu N.
6个回答

5

太好了! 刚刚删除了所有不必要的代码。

int main()
{    
    ifstream in("example.txt");
    int LineCount = 0;
    char* str = new char[500];

    while(in)
    {
        LineCount++;
        in.getline(str, 255);
        char * tempPtr = strtok(str," ");
        while(tempPtr)
        {
            AddWord(tempPtr, LineCount);
            tempPtr = strtok(NULL," ,.");
        }
    }
    in.close();
    delete [] str;
    cout<<"Total No of lines:"<<LineCount<<endl;
    showData();

    return 0;
}

顺便提一下,原始问题陈述是创建一个索引程序,该程序将接受用户文件并创建所有单词的行索引。


请不要使用strtok。一旦您需要编写多线程代码,它会立即反噬您。一个好的替代品是使用标准C++的std :: istringstream。 - Tom

4

我还没有尝试编译这个,但是有一个替代方案,几乎就像使用Boost那样简单,但不需要额外的依赖。

#include <iostream>
#include <sstream>
#include <string>

int main() {
  std::string line;
  while (std::getline(std::cin, line)) {
    std::istringstream linestream(line);
    std::string word;
    while (linestream >> word) {
      std::cout << word << "\n";
    }
  }
  return 0;
 }

+1 这就是我会做的。现在只需要插入计数器,就完成了。 - Frank

0

类似这样的例子已经在互联网上出现了很多。这是我在高中写的一个计算单词数的程序,可以用它作为起点。我想指出的其他事情是:

std::stringstream:你可以使用std::getline获取整个行,然后使用std::stringstream将其分解成更小的片段并进行标记化处理。您可以使用std::getline获取整个行并将其输入到std::string中,然后将其传递给std::stringstream。

再次强调,这只是一个示例,并不能完全满足您的要求,您需要自己修改它以使其符合您的要求!

#include <iostream>
#include <map>
#include <string>
#include <cmath>
#include <fstream>

// Global variables
        std::map<std::string, int> wordcount;
        unsigned int numcount;

void addEntry (std::string &entry) {
        wordcount[entry]++;
        numcount++;
        return;
}


void returnCount () {
        double percentage = numcount * 0.01;
        percentage = floor(percentage + 0.5f);

        std::map<std::string, int>::iterator Iter;

        for (Iter = wordcount.begin(); Iter != wordcount.end(); ++Iter) {
                if ((*Iter).second > percentage) {
                        std::cout << (*Iter).first << " used " << (*Iter).second << " times" << std::endl;
                }
        }

}

int main(int argc, char *argv[]) {
        if (argc != 2) {
                std::cerr << "Please call the program like follows: \n\t" << argv[0] 
                        << " <file name>" << std::endl;
                return 1;
        }

        std::string data;

        std::ifstream fileRead;
        fileRead.open(argv[1]);
        while (fileRead >> data) {
                addEntry(data);
        }
        std::cout << "Total words in this file: " << numcount << std::endl;
        std::cout << "Words that are 1% of the file: " << std::endl;
        returnCount();
}

你好, 感谢Blorgbeard、Reed和X-Istence的快速回复。 我不仅需要解析行,还需要跟踪行号。问题陈述是要制作一个单词列表,其中包含它们出现的行号。 - Rocco Lampone
Ravi:我刚才给你的代码可以帮你完成一半的工作。我们不是来替你做作业的! - X-Istence
哦,不!那不是我的意图。我只是在第一部分遇到了麻烦。一旦解决了这个问题,我打算自己完成剩下的部分。 - Rocco Lampone

0
如果您可以使用boost库,我建议使用boost::tokenizer

The boost Tokenizer package provides a flexible and easy to use way to break of a string or other character sequence into a series of tokens. Below is a simple example that will break up a phrase into words.

// simple_example_1.cpp
#include<iostream>
#include<boost/tokenizer.hpp>
#include<string>

int main(){
   using namespace std;
   using namespace boost;
   string s = "This is,  a test";
   tokenizer<> tok(s);
   for(tokenizer<>::iterator beg=tok.begin();beg!=tok.end();++beg){
       cout << *beg << "\n";
   }
}

0
ifstream is {"my_file_path"}; 
vector<string> b {istream_iterator<string>{is},istream_iterator<string>{}};

不要忘记包含这个:
<iterator>

0

尝试将您的cout<<t2<<end;语句移动到while循环中。

这应该使您的代码基本上可用。

您可能想查看此类似帖子以获取其他方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接