C++函数计算字符串中的所有单词

evi*_*ack 14 c++ string

我在接受采访时被问到这一点,显然这是一个简单的问题,但对我而言并不是,现在仍然不明显.

给定一个字符串,计算其中的所有单词.如果重复它们无关紧要.只是文本文件中的总计数字数.单词是由空格分隔的任何东西,标点符号无关紧要,只要它是单词的一部分.

例如: A very, very, very, very, very big dog ate my homework!!!! ==> 11 words

我的"算法"只是查找空格并递增计数器直到我达到空值.既然我没有得到这份工作,之后被要求离开,我想我的解决方案并不好?谁有更聪明的解决方案?我错过了什么吗?

Mar*_*ork 35

假设单词是空格分隔的:

unsigned int countWordsInString(std::string const& str)
{
    std::stringstream stream(str);
    return std::distance(std::istream_iterator<std::string>(stream), std::istream_iterator<std::string>());
}
Run Code Online (Sandbox Code Playgroud)

注意:单词之间可能有多个空格.此外,它不会捕获其他空格字符,如制表符新行或回车符.因此计算空间是不够的.

流输入运算符>>用于从流中读取字符串时.读取一个空格分隔的单词.所以他们可能正在寻找你用它来识别单词.

std::stringstream  stream(str);
std::string        oneWord;

stream >> oneWord; // Reads one space separated word.
Run Code Online (Sandbox Code Playgroud)

何时可以使用它来计算字符串中的单词.

std::stringstream  stream(str);
std::string        oneWord;
unsigned int       count = 0;

while(stream >> oneWord) { ++count;}
// count now has the number of words in the string.
Run Code Online (Sandbox Code Playgroud)

变得复杂:
流可以像任何其他容器一样处理,并且有迭代器来循环它们std :: istream_iterator.在istream_iterator上使用++运算符时,它只需使用运算符>>从流中读取下一个值.在这种情况下,我们正在读取std :: string,因此它读取一个空格分隔的单词.

std::stringstream  stream(str);
std::string        oneWord;
unsigned int       count = 0;

std::istream_iterator loop = std::istream_iterator<std::string>(stream);
std::istream_iterator end  = std::istream_iterator<std::string>();

for(;loop != end; ++count, ++loop) { *loop; }
Run Code Online (Sandbox Code Playgroud)

使用std :: distance只需将所有上述内容包装在一个整洁的包中,因为它通过在第一个上面执行++来找到两个迭代器之间的距离,直到我们到达第二个.

为了避免复制字符串,我们可以偷偷摸摸:

unsigned int countWordsInString(std::string const& str)
{
    std::stringstream stream;

    // sneaky way to use the string as the buffer to avoid copy.
    stream.rdbuf()->pubsetbuf (str.c_str(), str.length() );
    return std::distance(std::istream_iterator<std::string>(stream), std::istream_iterator<std::string>());
}
Run Code Online (Sandbox Code Playgroud)

注意:我们仍将原文中的每个单词复制为临时单词.但是成本很低.

  • *易于阅读*为谁?作者还是未知的维护者?(这可能是一个雇佣的地方要求人们知道C++标准库,但我还没有被这样的设施雇用.:))(注意我认为这是一个很好的解决方案,但是已经离我很远了从适当的C++中长久以来,让我惊讶地遇到它.) (2认同)
  • @ dash-tom-bang:呃..要求一个C++程序员并期望他们不懂C++是不合理的.标准库是C++的一部分. (2认同)
  • @ dash-tom-bang:我希望任何人都可以轻松阅读。标准库的全部要点是每个人都使用而不是发明自己的库。因此,即使您不知道距离,您也可以在二十秒钟内查找它,使用迭代器可以看到它,这样我们就可以推断出我们是在溪流中进行迭代,并让您的叔叔bo了一下。代码在30秒内得出。 (2认同)

das*_*ang 7

一个不太聪明,更明显的所有程序员在团队中的方法.

#include <cctype>

int CountWords(const char* str)
{
   if (str == NULL)
      return error_condition;  // let the requirements define this...

   bool inSpaces = true;
   int numWords = 0;

   while (*str != '\0')
   {
      if (std::isspace(*str))
      {
         inSpaces = true;
      }
      else if (inSpaces)
      {
         numWords++;
         inSpaces = false;
      }

      ++str;
   }

   return numWords;
}
Run Code Online (Sandbox Code Playgroud)

  • 这是我希望作为采访者看到的答案.当某人要求某人在面试中实施一个简单的算法时,面试官通常会试图看看这个人是否可以在不引入不必要的开销,复杂性或混淆的情况下理智地编写一段低级代码.他们并没有试图通过模糊的图书馆功能进行鸡巴测量比赛,也没有向受访者挑战高尔夫代码游戏. (8认同)
  • 它的相对标准是使用流运算符>>来获取单词.我不明白这是如何更明显的,因为它需要一段时间来阅读所有这些代码并理解它. (5认同)

Chr*_*unt 5

另一个可以工作的基于提升的解决方案(未经测试):

vector<string> result;
split(result, "aaaa bbbb cccc", is_any_of(" \t\n\v\f\r"), token_compress_on);
Run Code Online (Sandbox Code Playgroud)

更多信息可以在Boost String Algorithms Library中找到

  • "虽然它有效,但这并不是我在采访中想要的." - 你的意思是说你会找一个想要永远写东西的人.;-)对你来说,详细说明你的评论对我很有帮助. (2认同)

The*_*ect 5

您可以使用std :: count或std :: count_if来执行此操作。下面是一个带有std :: count的简单示例:

//Count the number of words on string
#include <iostream>
#include <string>
#include <algorithm> //count and count_if is declared here

int main () {
    std::string sTEST("Text to verify how many words it has.");

    std::cout << std::count(sTEST.cbegin(), sTEST.cend(), ' ')+1;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

更新:由于AydinÖzcan(11月16日)的观察,我对该解决方案进行了更改。现在,单词之间可能有多个空格。:)

//Count the number of words on string
#include <string>
#include <iostream>

int main () {
    std::string T("Text to   verify :  How many words does it   have?");

    size_t NWords = T.empty() || T.back() == ' ' ? 0 : 1;
    for (size_t s = T.size(); s > 0; --s)
        if (T[s] == ' ' && T[s-1] != ' ') ++NWords;

    std::cout << NWords;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)