在C ++中清理标点字符串

时间:2020-03-06 14:33:14  来源:igfitidea点击:

好的,所以在我问我的问题之前,我想澄清一件事。我目前是NIU的计算机科学专业的学生,​​这与我在那里的一堂课有关。因此,如果有人遇到问题,请继续阅读,然后继续进行业务。

现在,对于愿意帮助解决这种情况的任何人。对于我当前的任务,我们必须读取一个只是文本块的文件。对于文件中的每个单词,我们都要清除单词中的所有标点符号(例如:"不能"最终以"可以"结尾,而"那-到"最终以"那个"结尾而没有引号,引号仅用于指定示例)。

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

因此,我要寻找的是两件事,关于如何解决该问题的任何建议,而不仅仅是消除它,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] != '
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;
'; i++); begin = i; if(begin ==(int)non_clean.length()) return; for(j = begin; isalnum(non_clean[j]) != 0 && non_clean[j] != '
not_s = "";
clean_entry(s, not_s);

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

input >>s;
'; j++); end = j; clean = non_clean.substr(begin, (end-begin)); for(i = 0; i < (int)clean.size(); i++) clean[i] = tolower(clean[i]); }

解决方案

空条目的问题在于while循环中。如果我们得到一个空字符串,请清理下一个,然后不检查就添加它。尝试更改:

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

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;
 }

编辑:我注意到我们正在检查字符是否为字母数字。如果不允许输入数字,则可能还需要重新访问该区域。

空字符串是字符串类的有效实例,因此将其添加到映射中没有什么特别的。我们可以做的是先检查它是否为空,然后在这种情况下才递增:

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

在样式方面,我需要更改一些内容,其中之一是从clean_entry返回clean而不是对其进行修改:

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

这样可以更清楚地知道函数在做什么(获取一个字符串,然后基于该字符串返回一些内容)。

进一步的改进将是

  • 仅在使用变量时并在最内部的范围内声明变量
  • 使用c ++样式强制转换而不是c样式(int)强制转换
  • 使用empty()代替length()== 0比较
  • 为迭代器使用前缀增量运算符(即" ++ mapzIter")

函数" getWords"正在执行许多不同的动作,这些动作可以分解为其他功能。通过将其拆分成单独的部分,我们很有可能自己发现了该错误。

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

  • getNextWord:返回流中的下一个(非空白)单词(如果没有,则返回false)
  • clean_entry:我们现在拥有的
  • getNextCleanWord:调用getNextWord,如果为" true",则调用CleanWord。如果没有剩余单词,则返回" false"。

" getNextWord"和" getNextCleanWord"的签名可能类似于:

##代码##

想法是,每个功能都在问题的较小部分中起着不同的作用。例如," getNextWord"除了获取下一个非空白单词(如果有)之外什么都不做。因此,如果需要的话,这个较小的部分将成为问题更容易解决和调试的部分。

然后可以将" getWords"的主要成分简化为:

##代码##

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