-1

テキスト ファイルを読み取る C++ プログラムを作成しました。ただし、単語が出現する回数をプログラムにカウントさせたいと考えています。たとえば、出力は次のようになります。

Word Frequency Analysis

Word          Frequency
I                1
don't            1
know             1
the              2
key              1
to               3
success          1
but              1
key              1
failure          1
is               1
trying           1
please           1
everybody        1

各単語が 1 回しか表示されないことに注目してください。この効果を達成するために何をする必要がありますか??

テキスト ファイルは次のとおりです (つまり、BillCosby.txt という名前です)。

I don't know the key to success, but the key to failure is trying to please everybody.

これまでの私のコードは次のとおりです。私は極度のメンタルブロックを抱えており、単語が出現する回数をプログラムに読み取らせる方法がわかりません。

#include <iostream>
#include <fstream>
#include <iomanip>

const int BUFFER_LENGTH = 256;
const int NUMBER_OF_STRINGS = 100;

int numberOfElements = 0;
char buffer[NUMBER_OF_STRINGS][BUFFER_LENGTH];
char * words = buffer[0];
int frequency[NUMBER_OF_STRINGS];

int StringLength(char * buffer);
int StringCompare(char * firstString, char * secondString);

int main(){

int isFound = 1;
int count = 1;

std::ifstream input("BillCosby.txt");

if(input.is_open())
{
    //Priming read
    input >> buffer[numberOfElements];
    frequency[numberOfElements] = 1;

while(!input.eof())
    {
    numberOfElements++;
    input >> buffer[numberOfElements];

    for(int i = 0; i < numberOfElements; i++){
        isFound = StringCompare(buffer[numberOfElements], buffer[i]);
            if(isFound == 0)
                ++count;
    }

    frequency[numberOfElements] = count;


    //frequency[numberOfElements] = 1;

    count = 1;
    isFound = 1;
    }
    numberOfElements++;
}
else
    std::cout << "File is not open. " << std::endl;

std::cout << "\n\nWord Frequency Analysis " << std::endl;
std::cout << "\n" << std::endl;

std::cout << "Word " << std::setw(25) << "Frequency\n" << std::endl;

for(int i = 0; i < numberOfElements; i++){
    int length = StringLength(buffer[i]);
    std::cout << buffer[i] << std::setw(25 - length) << frequency[i] << 

 std::endl;
}



return 0;
}

int StringLength(char * buffer){
char * characterPointer = buffer;

while(*characterPointer != '\0'){
    characterPointer++;
}

return characterPointer - buffer;
}

int StringCompare(char * firstString, char * secondString)
   {
    while ((*firstString == *secondString || (*firstString == *secondString - 32) ||    

(*firstString - 32 == *secondString)) && (*firstString != '\0'))
{
    firstString++;
    secondString++;
}

if (*firstString > *secondString)
    return 1;

else if (*firstString < *secondString)
    return -1;

return 0;
}
4

5 に答える 5

4

あなたのプログラムは非常に読みにくいです。しかし、この部分は私に突き出ました:

frequency[numberOfElements] = 1;

(while ループ内)。単語が何回表示されても、常に頻度を 1 に設定していることに気付きましたか? たぶん、値を 1 に設定するのではなく、インクリメントするつもりでしたか?

于 2013-01-21T04:20:09.190 に答える
3

1 つのアプローチは、トークン化 (行を単語に分割) してから、c++ マップ コンテナーを使用することです。マップには、単語がキーとして、単語数が値として含まれます。

トークンごとにマップに追加し、単語数を増やします。マップ キーは一意であるため、重複はありません。

トークナイザーにはstringstreamを使用できます。マップ コンテナーのリファレンス (例を含む) は、こちら にあります

心配しないでください。優れたプログラマーは日常的にメンタル ブロックに対処しています。ですから、それに慣れてください :)

于 2013-01-21T04:17:34.530 に答える
0

ソリューションのフローは次のようになります。-ストレージを初期化します(明らかに非常に小さなファイルがあることをご存知ですか?)-初期カウントをゼロ(1ではない)に設定します-単語を配列に読み込みます。新しい単語を取得したら、すでにそれを持っているかどうかを確認します。その場合は、その場所のカウントに1を追加します。そうでない場合は、それを単語のリストに追加し( "hey --a new word!")、そのカウントを1に設定します-ファイル内のすべての単語をループします

空白に注意してください-空白以外の文字のみに一致することを確認してください。今、あなたは「鍵」を2回持っています。それは間違いだと思いますか?

幸運を。

于 2013-01-21T04:25:19.147 に答える
0

codepad.org でテストしたコード例を次に示します。

#include <iostream>
#include <map>
#include <string>
#include <sstream>

using namespace std;

int main()
{
string s = "I don't know the key to success, but the key to failure is trying to please everybody.";
string word;
map<string,int> freq;

for ( std::string::iterator it=s.begin(); it!=s.end(); ++it)
{
    if(*it == ' ')
    {
         if(freq.find(word) == freq.end()) //First time the word is seen
         {
             freq[word] = 1;
         }
         else //The word has been seen before
         {
             freq[word]++;
         }
         word = "";
    }
    else
    {
         word.push_back(*it);
    }
}

for (std::map<string,int>::iterator it=freq.begin(); it!=freq.end(); ++it)
    std::cout << it->first << " => " << it->second << '\n';

}

スペースを見つけると停止するため、文法記号が混乱しますが、要点はわかります。

出力:

I => 1
but => 1
don't => 1
failure => 1
is => 1
key => 2
know => 1
please => 1
success, => 1コンマ。ただし、簡単な変更でこれを修正できます。//ご自身で判断してください。
=> 2
から => 3 を
試す => 1

于 2013-01-21T04:31:11.353 に答える
0

宿題によく似たものに直接の回答を投稿するのは少しためらいますが、誰かがこれを宿題として提出した場合、中途半端な教師/教授はかなり真剣な説明を要求するだろうと確信しています。そうする場合は、注意深く調べて、すべての部品が何であり、どのように機能するかについての深刻な質問に備える必要があります。

#include <map>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <string> 
#include <fstream>
#include <iomanip>
#include <locale>
#include <vector>

struct alpha_only: std::ctype<char> {
    alpha_only() : std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table() {
        static std::vector<std::ctype_base::mask> 
            rc(std::ctype<char>::table_size,std::ctype_base::space);
        for (int i=0; i<std::ctype<char>::table_size; i++)
            if (isalpha(i)) rc[i] = std::ctype_base::alpha;
        return &rc[0];
    }
};

typedef std::pair<std::string, unsigned> count;

namespace std { 
    std::ostream &operator<<(std::ostream &os, ::count const &c) { 
        return os << std::left << std::setw(25) << c.first 
                  << std::setw(10) << c.second;
    }
}

int main() { 
    std::ifstream input("billcosby.txt");
    input.imbue(std::locale(std::locale(), new alpha_only()));

    std::map<std::string, unsigned> words;

    std::for_each(std::istream_iterator<std::string>(input),
                    std::istream_iterator<std::string>(),
                    [&words](std::string const &w) { ++words[w]; });
    std::copy(words.begin(), words.end(),
              std::ostream_iterator<count>(std::cout, "\n"));
    return 0;
}
于 2013-01-21T06:00:05.990 に答える