0

这是文件的内容:

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

要求是从文本文件中读取每一行,然后从行中提取单词。每当遇到一个新单词时,程序应该从动态内存中分配一个节点实例来包含该单词及其计数,并将其插入到一个链表中,以便该列表始终是排序的。如果遇到的单词已经存在于列表中,那么该单词的计数应该增加。考虑到'。分隔符,如果 . 字符在左边有一个空格、制表符、换行符或数字,在右边有一个数字,那么它被视为小数点,因此是单词的一部分。否则,它将被视为句号和单词分隔符。

单词:是由一个或多个分隔符序列分隔的字母和数字字符、单引号、下划线和连字符的序列。请参阅下面的分隔符列表。此分配的输入将由单词、整数和浮点数组成。单引号字符将始终充当撇号,并应被视为单词的一部分。因此,streamer、streamers、streamer's 和 streamers' 都应该是不同的词,但是“streamers”和 streamers 应该算作词 streamers 的两次出现。

显然,我在下面得到了一些东西,但我仍然坚持将句点视为单词分隔符。谁能给我一些提示?

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 来存储节点和一些基本的字符串操作。

4

1 回答 1

0

我已经修改了您编写的函数(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.

对于我已经修改了代码的加载函数,您的部分是确定在我的代码中插入列表节点的代码并将其与您的需要集成,这里是修改的加载函数:

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并将多余的ifs分组。
4-最后这一切都取决于你的逻辑和你的思维方式。

祝你好运 :)

注意我using namespace std;每次都使用该语句而不是嵌入 std:: 。如果我错了,请纠正我。

于 2012-04-29T08:38:52.190 回答