【问题标题】:Read through chars in a file and count how many individual letters there are [c++]通读文件中的字符并计算有多少个单独的字母 [c++]
【发布时间】:2015-04-30 17:38:08
【问题描述】:

所以用户将输入一个包含任何文本的文件,程序需要通读每个字符并计算每个字符的数量(仅限大写和小写字母)。所以,可能有 50 个 A,23 个 b,等等......

这是我目前在 main.cc 中的内容:

    char character;
    int i = 65; //this is the iterator to go through upper and lowercase letters
    int count = 0; //counts number of characters and resets when exiting the loop and after using cout
    ifstream file(filename); //filename is a string the user inputs
    while (i != 0) {
        while (file >> character) {
            int a = character;
            cout << a << endl; //testing: outputs the correct number for the letter
            if (i == a) { //but for some reason this part isn't working?
                count++;
            }
        }
        cout << count << endl; //this outputs 0 every time
        count = 0;
        i++;
        if (i == 91)  i = 97;  //switch to lower case
        if (i == 123) i = 0;   //exit loop
    }

感谢您的帮助!谢谢:)

【问题讨论】:

  • 我认为 file>> 字符给出了单词而不是字符。因此,当您执行 int a = character 时,您实际上错过了其余字符。
  • @InQusitive: characterchar 类型,所以file &gt;&gt; character 只会读取单个字符,而不是整个单词。
  • 问题atm是,您在寻找第一个字符('A')时将文件读到最后,然后文件流已达到EOF!所以不会有任何数据留在流中。我也会在 (!file.eof())
  • @Andy:或者只是一个数组
  • 尼德霍格,你说得对。它只经过一次内部循环并且不会返回。现在想出一种不同的方法来做到这一点......

标签: c++ char ifstream


【解决方案1】:

让我们假设文本是 ASCII 或扩展 ASCII,因此最多有 256 个可能的字符。

您可以使用数组来保存给定字符的出现次数。每个插槽对应一个字符;相反,字符可以用作数组的索引。

例子:

unsigned int MAXIMUM_CHAR_VALUES = 256U;
unsigned int occurrences[MAXIMUM_CHAR_VALUES] = {0};
char c;
while (my_text_file >> c)
{
  ++occurrences[c];
}
// Print them out
for (unsigned int i = 0; i < MAXIMUM_CHAR_VALUES; ++i)
{
  if (!isprint(i))
  {
    cout << "0x" << hex << i;
  }
  else 
  {
    c = static_cast<char>(i);
    cout << c;
  }
  cout << ":  " << occurrences[i] << "\n";
}

如果您必须使用“节点”,您可以将数组更改为节点数组。

还有其他可以使用的结构,例如二叉树。

【讨论】:

    【解决方案2】:

    这是使用地图的理想场所

    从文件中读取一个字符

    file >> character;
    

    地图位置的增量

    if( isalpha(character) ) { myMap[character]++; }
    

    最后,您可以遍历所有地图条目并将它们全部打印出来。

    for(map<char, int >::const_iterator it = myMap.begin(); it != myMap.end(); ++it)
    {    
        std::cout << "The character " << it->first << " was found " << it->second<< " times." << std::endl;
    }
    

    【讨论】:

    • 我会添加一个检查以确定字符是否为字母,使用isalpha,仅当字符为字母时才更新地图。
    • 为什么文件 >> 字符只能获取每个单词的第一个字母?只需循环它并一次读取一个字符
    • file >> 字符读取每个字母。我可以再次测试以仔细检查。编辑:是的...它通读每个字母
    • IMO,std::map 太过分了。数组而不是向量更有效。字符值可以用作计数数组的索引。简单,单一访问。地图或树必须读取一个节点,决定,读取更多节点,然后最终在节点中增加一个值。比访问数组中的插槽要多得多。
    • 是的,地图可能有点矫枉过正,但并没有你说的那么糟糕。地图的访问时间为 O(log(n))。如果我们允许 n 为 52(总字母字符数),那么结果为 O(1.7),并不可怕。
    【解决方案3】:

    感谢其他答案,我想出了这种方法......到目前为止它工作得很好。谢谢各位!

    char character;
    int a[256] = {0};
    int i = 65;
    ifstream file(filename);
    
    while (file >> character) {
        a[character]++;
    }
    
    while (i != 0) {
        character = i;
        cout << "There are " << a[i] << " of " << character << endl;
        i++;
        if (i == 91) i = 97;
        if (i == 123) i = 0;
    }
    

    【讨论】:

    • i == 91i == 123 行(和 i = 65;)难以理解且写得不好。使用if (i == 'Z') i = 'a'; if (i == 'z') i = 0; 会更加清晰,但是还有比这更好的方法来控制循环,特别是如果您不必担心小写字母出现的EBCDIC 等古怪的代码集在大写字母之前(并且都在数字之前)。
    猜你喜欢
    • 2019-11-03
    • 1970-01-01
    • 1970-01-01
    • 2019-04-21
    • 1970-01-01
    • 2014-10-17
    • 2023-02-21
    • 2023-03-20
    • 2016-07-25
    相关资源
    最近更新 更多