簡體   English   中英

來自文本文件的單詞計數C ++

[英]Word count from a text file c++

這是文件的內容:

12.34.
.3
3..3
.3.4
..8
.this
test.this
test.12.34
test1.this
test1.12.34

這是預期的輸出:

COUNT | WORD 
------+------
   1  | .3
   1  | .3.4
   2  | 12.34
   2  | 3
   1  | 8
   2  | test
   1  | test1
   1  | test1.12.34
   3  | this

要求是從文本文件中讀取每一行,然后從該行中提取單詞。 每當遇到新單詞時,程序應從動態內存中分配該節點的實例以包含該單詞及其計數,然后將其插入鏈接列表,以便始終對列表進行排序。 如果列表中已經存在遇到的單詞,則該單詞的計數應增加。 考慮“。” 分隔符(如果有)。 字符左邊有空格,制表符,換行符或數字,右邊有數字,則將其視為小數點,因此是單詞的一部分。 否則,它將被視為句號和單詞分隔符。

單詞:是由一個或多個分隔符字符序列分隔的字母和數字字符序列,單引號,下划線和連字符。 請參見下面的分隔符列表。 此分配的輸入將由單詞和整數以及浮點數組成。 單引號字符將始終充當撇號,並且應被視為單詞的一部分。 因此,飄帶,飄帶,飄帶和飄帶都應該是不同的詞,但是“飄帶”和飄帶應該算作單詞飄帶的兩次出現。

顯然,我在下面得到了一些東西,但是我仍然堅持將句點視為單詞分隔符。 有人可以給我一些提示嗎?

bool isSeparator(const char c) {  
    if (std::isspace(c)) return true;

    const std::string pattern = ",;:\"~!#%^*()=+[]{}\\|<>?/";
    for (unsigned int i = 0; i < pattern.size(); i++) {
        if (pattern[i] == c) 
            return true;
    }
    return false;
}
void load(std::list<Node> &nodes, const char *file) {
    std::ifstream fin;
    std::string line = "";
    std::string word = "";

    fin.open(file);

    while (std::getline(fin, line)) {

        for (unsigned int i = 0; i < line.size(); i++) {
            if (isSeparator(line[i]) || i == (line.size() - 1)) {
                if (word.find('.') < word.size()) { // if there is a '.' in a word
                    if (word.find('.') == word.size() - 1) { // if '.' at the end of word
                        word.erase(word.find('.'), 1); // remove '.' in any case
                    }
                }
                if (word.size() != 0) {
                    nodes.push_back(Node(word));
                    word.clear();
                }
            } else {
                word += line[i];
            }
        }
    }

    fin.close();
}

我只是剛開始使用c ++,所以分配僅需要使用std :: list來存儲節點和一些基本的字符串操作。

我已經修改了您編寫的函數(isSeparator),並添加了一個新函數(isDigit):

bool isSeparator(const char c) {
    const string pattern = ".,;:\"~!#%^*()=+[]{}\\|<>?/";
    for (unsigned int i = 0; i < pattern.size(); i++) {
        if (pattern[i] == c)
            return true;
    }
    return false;
}

bool isDigit(const char c) {
    if ((int) c >= 0x30 && (int) c <= 0x39) return true;
    else return false;
}

新功能isDigit用於確定傳遞的字符是否為數字,我嘗試收集所有可能的測試用例,以確保您以正確的方式分隔單詞,這是我考慮的情況:

word.12word.word
word.12.3word.word
word.word12.word
12.3.

對於我已經修改了代碼的load函數,您的部分是確定將哪些代碼插入到我的代碼的list節點中,並將其與您的需求集成,這是修改后的load函數:

ifstream fin;
    fin.open("file.in");
    string line, word = "";
    list<Node> node;
    while (getline(fin, line)) {
        for (unsigned int i=0; i<line.size(); i++) {
            if ((line[i] == '\t' || line[i] == ' ' || isDigit(line[i])) && (line[i+1]=='.' && isDigit(line[i+2]))) {
                word += line[i];
                word += ".";
                i+=2;
                while (!isSeparator(line[i])) word += line[i++];
                i--;
            } else if (!isSeparator(line[i])) {
                word += line[i];
                if (i==line.size()-1) {
                    node.push_back(Node(word));
                    //cout << word << endl; for debugging
                    word.clear();
                }
            } else {
                if (word.size() > 0) {
                    node.push_back(Node(word));
                    //cout << word << endl; for debugging
                    word.clear();
                }
            }
        }
    }
    fin.close();

這是輸出:

word
12word
word
word
12.3word
word
word
word12
word
12.3

為了解決這些字符串匹配問題,您必須遵循以下步驟:

1-首先確定可能的情況,我想我提供的測試用例證明了這一點。
2-根據可能的測試用例/輸入開始構建ifs語句。
3-嘗試減少ifs並將多余的分組。
4-最后,這取決於您的邏輯和思維方式。

祝好運 :)

注意我使用過using namespace std; 而不是每次嵌入std ::語句。 如果我錯了,請糾正我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM