如何从C ++中的简单句子中计算单词和数字

时间:2016-01-25 22:57:28

标签: c++

我是c ++的初学者(花了几个课,然后一段时间没有c ++,然后几个月后重新开始),我试着用一个简单的句子计算单词的数量,然后计算同一句话中的数字。为了计算单词,我使用:

int countWord(char *word)
    {
     int counter = 0;
     char *words = strtok(word, " 0123456789-");

     while (words != NULL)
        {
            counter++;
            words = strtok(NULL, " 0123456789-");
        }
    return counter;
    }

数字计数器基本相同,而不是使用整数我使用字母表。

char *num = strtok(number, " abcdefghijklmnopqrstuvwxyz");

我的主要是:

int main()
{
    char str[] = "what time is 88 it 99today";

    cout << "words = " << countWord(str) << " " << "numbers = " <<
    countNum(str) << endl;          

    system("pause");

    return 0;
}

当我运行它时输出:words = 3 numbers = 2.

当我将主要重新排列为:

    char str[] = "what time is 88 it 99today";

    cout << "words = " << countWord(str) << " ";
    cout << "numbers = " << countNum(str) << endl;

输出为:words = 5 numbers = 0

任何人都可以解释为什么这是不正确的?此外,如果有人可以推荐我的文字,我会很感激。我从中学到的文字是:“C ++编程:D.S.Malik编写的包含数据结构的程序设计。我在本书中没有看到任何计算”单词“的技巧。谢谢。

2 个答案:

答案 0 :(得分:2)

问题是strtok用空字符标记原始字符串中的标记结束。引自cppreference

  

如果找到这样的字符,它将被替换为空字符'\ 0',并且指向后面字符的指针存储在静态位置以供后续调用。

     

注意:此函数具有破坏性:它将'\ 0'字符写入字符串str的元素中。特别是,字符串文字不能用作strtok的第一个参数。

在你的情况下,行

cout << "words = " << countWord(str) << " " << "numbers = " <<
countNum(str) << endl;

operator<<的组合,如

...operator<<(operator<<(cout, "words"), countWord(str))...

首先评估第countNum(str)行。然后,第二次评估countWord(str)。这与

形成对比
cout << "words = " << countWord(str) << " ";
cout << "numbers = " << countNum(str) << endl;

其他方式发生。

一种解决方案是在使用strtok时使用原始字符串的副本,例如每次都使用strtok(strdup(str))。更好的是,使用标准的C ++库特性,如std::stringstd::count_if等。我确信有很多关于使用纯C ++的字数统计解决方案。

答案 1 :(得分:1)

Vlad为您的C风格代码提交了一个很好的答案。我的答案是展示使用更多的C ++库来帮助解决问题:

#include <iostream>
#include <string>
#include <vector>
#include <regex>

int main() {
    // The main string.
    std::string str = "what time is 88 it 99today"; 
    // Space is your delimiter
    std::string delimiter = " ";
    // Create a regex string for matching numbers, including floating point.
    std::regex number_chars(std::string("[0123456789.]+"));

    // A lambda function to help tokenize strings.
    // Returns a vector of substring tokens.
    // The internal code is taken from an answer on Stack Overflow.
    auto tokenizer = [](std::string s, std::string delimiter) {
        size_t pos = 0;
        std::string token;
        std::vector<std::string> tokens;

        while (pos = (s.find(delimiter))) {
            token = s.substr(0, pos);
            tokens.push_back(token);
            s.erase(0, pos + delimiter.length());

            if (pos == std::string::npos)
                break;

        }
        return tokens; 
    };

    // Apply the lambda.
    auto tokens = tokenizer(str, delimiter);

    // Output your tokens.
    for (auto it : tokens) {
        std::cout << it << "\n";    
    } std::cout << "\n";

    // Output tokens that are numbers.
    for (auto it : tokens) {
        if (std::regex_match(it, number_chars)) {
            std::cout << "String: " << it << " is a number.\n";    
        }
    }
    return 0;
}

由于C ++在C ++ 11中有一个正则表达式库,因此利用它会很好。

Coliru:http://coliru.stacked-crooked.com/a/43cd6711e1243f4a