用C ++清理一串标点符号

时间:2008-09-22 18:07:03

标签: c++

好的,所以在我问我的问题之前我想说清楚一件事。我目前是NIU计算机科学专业的学生,​​这与我在那里的课程作业有关。因此,如果有人有问题,请不要再阅读,继续关注您的业务。

现在,对于任何愿意帮助这种情况的人来说。对于我目前的作业,我们必须阅读一个只是一个文本块的文件。对于文件中的每个单词,我们要清除单词中的任何标点符号(例如:“不能”将最终为“can”,“that - to”将最终显示为“that”,显然没有引号,引号仅用于指定示例的内容。

我遇到的问题是我可以清理字符串,然后将其插入到我们正在使用的地图中但由于某些原因我编写的代码允许将空字符串插入到地图。现在我已经尝试了所有可以阻止这种情况发生的事情,我唯一想到的就是在地图结构中使用擦除方法。

所以我正在寻找的是两件事,关于我如何能够解决这个问题的任何建议,只需简单地删除它,以及b)我可以对已编写的代码进行任何改进。

以下是我从文件中读取的函数,然后是清理它的函数。

注意:从文件读入的函数调用clean_entry函数以在将任何内容插入到地图之前去掉标点符号。

编辑:谢谢克里斯。数字是允许的:)。如果有人对我写的代码有任何改进,或者对我所做的事情有任何批评,我会听。在学校,我们确实没有得到正确,适当或最有效的做事方式的反馈。

int get_words(map<string, int>& mapz)
{
 int cnt = 0;               //set out counter to zero

 map<string, int>::const_iterator mapzIter;

 ifstream input;            //declare instream
 input.open( "prog2.d" ); //open instream
 assert( input );           //assure it is open

 string s;                  //temp strings to read into
 string not_s;

 input >> s;

 while(!input.eof())        //read in until EOF
  {
   not_s = "";
   clean_entry(s, not_s);

   if((int)not_s.length() == 0)
    {
     input >> s;
     clean_entry(s, not_s);
    }    

   mapz[not_s]++;              //increment occurence
   input >>s;
  }
 input.close();     //close instream 

 for(mapzIter = mapz.begin(); mapzIter != mapz.end(); mapzIter++)
  cnt = cnt + mapzIter->second;

 return cnt;        //return number of words in instream
}


void clean_entry(const string& non_clean, string& clean)
{
 int i, j, begin, end;

 for(i = 0; isalnum(non_clean[i]) == 0 && non_clean[i] != '\0'; i++);

 begin = i;

 if(begin ==(int)non_clean.length())
   return;

 for(j = begin; isalnum(non_clean[j]) != 0 && non_clean[j] != '\0'; j++);

 end = j;

 clean = non_clean.substr(begin, (end-begin));

 for(i = 0; i < (int)clean.size(); i++)
  clean[i] = tolower(clean[i]);

}

4 个答案:

答案 0 :(得分:7)

空条目的问题出在你的while循环中。如果你得到一个空字符串,你清理下一个字符串,并添加它而不检查。尝试更改:

not_s = "";
clean_entry(s, not_s);

if((int)not_s.length() == 0)
 {
  input >> s;
  clean_entry(s, not_s);
 }    

mapz[not_s]++;              //increment occurence
input >>s;

not_s = "";
clean_entry(s, not_s);

if((int)not_s.length() > 0)
{
    mapz[not_s]++;              //increment occurence
}    

input >>s;
编辑:我注意到你正在检查这些字符是否是字母数字。如果不允许使用数字,您可能还需要重新访问该区域。

答案 1 :(得分:2)

进一步改善

  • 仅在您使用变量时声明变量,并在最里面的范围
  • 中声明变量
  • 使用c ++ - 样式转换而不是c-style(int)转换
  • 使用empty()而不是length()== 0比较
  • 对迭代器使用前缀增量运算符(即++mapzIter

答案 2 :(得分:1)

空字符串是字符串类的有效实例,因此将其添加到地图中没有什么特别之处。你能做的是首先检查它是否为空,只在这​​种情况下增加:

if (!not_s.empty())
    mapz[not_s]++;

样式方面,我会改变一些事情,一个是从clean_entry返回清理而不是修改它:

string not_s = clean_entry(s);
...
string clean_entry(const string &non_clean)
{
    string clean;
    ... // as before 
    if(begin ==(int)non_clean.length())
        return clean;
    ... // as before
    return clean;
 }

这使得函数更清楚(取一个字符串,并根据该字符串返回一些内容)。

答案 3 :(得分:1)

函数'getWords'正在执行许多可以分解为其他函数的不同操作。很有可能通过将它分成它的各个部分,你会自己找到它。

从基本结构来看,我认为你可以将代码分成(至少):

  • getNextWord:从流中返回下一个(非空白)单词(如果没有,则返回false)
  • clean_entry:你现在拥有什么
  • getNextCleanWord:调用getNextWord,如果'true'调用CleanWord。如果没有留下任何单词,则返回'false'。

'getNextWord'和'getNextCleanWord'的签名可能如下所示:

bool getNextWord (std::ifstream & input, std::string & str);
bool getNextCleanWord (std::ifstream & input, std::string & str);

这个想法是每个函数在问题中扮演一个更小的更明显的部分。例如,'getNextWord'除了获取下一个非空白单词(如果有空单词)外什么都不做。因此,如果需要,这个较小的部分将成为解决和调试问题的一个更容易的部分。

'getWords'的主要组成部分可以简化为:

std::string nextCleanWord;
while (getNextCleanWord (input, nextCleanWord))
{
  ++map[nextCleanWord];
}

恕我直言,发展的一个重要方面是试图分而治之。将其拆分为需要执行的各个任务。这些子任务将更容易完成,也应该更容易维护。