【问题标题】:C++ searching a line from a file for certain words and then inserting a word after those wordsC ++从文件中搜索一行以查找某些单词,然后在这些单词之后插入一个单词
【发布时间】:2015-02-13 19:55:20
【问题描述】:

我对 C++ 非常陌生,并且我已经挣扎了很长一段时间试图弄清楚如何解决这个问题。基本上,我需要从文件中读取并找到一篇文章的所有实例(“a”,“A”,“an”,“aN”,“An”,“AN”,“the”,“The”, tHe","theE","THe","tHE","TheE","THE"),然后在那篇文章后面插入一个形容词。形容词的大小写必须基于文章前面的单词。例如,如果我找到“a SHARK”,我需要将其设为“HAPPY SHARK”。谁能告诉我最好的方法是什么?到目前为止,我已经放弃了很多想法,这就是我现在所拥有的,尽管我认为我不能这样做:

#include <iostream>
#include <string>
#include <cctype>
#include <fstream>
#include <sstream>

using namespace std;

void
usage(char *progname, string msg){
    cerr << "Error: " << msg << endl;
    cerr << "Usage is: " << progname << " [filename]" << endl;
    cerr << " specifying filename reads from that file; no filename reads standard input" << endl;
}

int main(int argc, char *argv[])
{
    string adj;
    string file;
    string line;
    string articles[14] = {"a","A","an","aN","An","AN","the","The","tHe","thE","THe","tHE","ThE","THE"};
    ifstream rfile;
    cin >> adj;
    cin >> file;
    rfile.open(file.c_str());
    if(rfile.fail()){
        cerr << "Error while attempting to open the file." << endl;
        return 0;
    }
    while(rfile.good()){
        getline(rfile,line,'\n');
        istringstream iss(line);
        string word;
        while(iss >> word){
            for(int i = 0; i <= 14; i++){
                if(word == articles[i]){
                    cout << word + " " << endl;
                }else{
                    continue;
                }
            }
        }
        }
  }

【问题讨论】:

  • 不要在.good() 上循环,而是在getline() 上循环。这是循环直到文件结束的流方式!
  • 好的,我改变一下,谢谢

标签: c++ file capitalization


【解决方案1】:

到目前为止,还不错,但如果您需要在行尾处理文章,那么逐行执行此操作可能会遇到麻烦。

不管怎样,在你匹配一篇文章之后,暂时忽略那个皱纹,那么首先你需要得到下一个单词,你需要根据它来确定你的大写。然后,您需要创建一个具有正确大小写的形容词的新字符串版本:

string adj_buf;  // big enough or dynamically allocate it based on adj

while(iss >> word){
    for(int i = 0; i <= 14; i++){
        if(word == articles[i]){
            cout << word + " ";
            iss >> word;  // TODO: check return value and handle no more words on this line
            adj_buf = adj;
            for (j = 0; j < word.size() && j < adj.size(); ++j)
                if (isupper(word[j]))
                    adj_buf[j] = toupper(adj[j]);
                else
                    adj_buf[j] = tolower(adj[j]);

            cout << adj_buf + " " + word;
            break;
        }
    }
}

回到我们忽略的皱纹。您可能不希望逐行执行此操作,然后逐个标记,因为处理这种特殊情况在您的控制中会很难看。相反,您可能希望在单个循环中逐个标记地执行此操作。

因此,您需要编写一个对文件进行操作的辅助函数或类,并可以为您提供下一个令牌。 (STL 中可能已经有这样一个类,我不确定。)无论如何,使用您的 I/O 可能看起来像:

struct FileTokenizer
{
    FileTokenizer(string fileName) : rfile(fileName) {}

    bool getNextToken(string &token)
    {
        while (!(iss >> token))
        {
            string line;

            if (!rfile.getline(rfile, line, '\n'))
                return false;

            iss.reset(line);  // TODO: I don't know the actual call to reset it; look it up
        }

        return true;
    }

private:
    ifstream      rfile;
    istringstream iss;
};

然后您的主循环将如下所示:

FileTokenizer tokenizer(file);

while (tokenizer.getNextToken(word))
{
    for(int i = 0; i <= 14; i++){
        if(word == articles[i]){
            cout << word + " ";

            if (!tokenizer.getNextToken(word))
                break; 

            adj_buf = adj;
            for (j = 0; j < word.size() && j < adj.size(); ++j)
                if (isupper(word[j]))
                    adj_buf[j] = toupper(adj[j]);
                else
                    adj_buf[j] = tolower(adj[j]);

            cout << adj_buf + " " + word;
            break;
        }
    }
}

您可能也想输出其余的输入?

【讨论】:

  • 不幸的是,我确实需要在行尾处理一篇文章。如果文件以一篇文章结尾,则不应在其后插入 adj。那么有没有更好的方法来搜索文件呢?
  • 是的,我刚刚发布了它:)
  • 如果我做了这样的事情怎么办? rfile.open(file.c_str()); if(rfile.fail()){ cerr > nextToken) { //cout
  • 处理起来有点棘手。如果你有背靠背的文章你应该怎么做:“a a SHARK”???为了正确处理这个问题,您可能需要将 peekNextToken() 添加到您的帮助程序类中,以便在找到文章匹配项时提取下一个单词。底层字符串流可能已经具有窥视功能。如果只是为了跳过比赛后不必要的比较,我还在内部添加了一个“中断”。
  • 如果它是“a a SHARK”,则需要是“a HAPPY a SHARK”
【解决方案2】:

首先我建议你使用 3 个辅助函数来转换字符串大小写。如果您大量使用文本,这些将很有用。这里他们基于&lt;algorithm&gt;many other aproaches are possible

string strtoupper(const string& s) {   // return the uppercase of the string
    string str = s; 
    std::transform(str.begin(), str.end(), str.begin(), ::toupper);
    return str; 
}
string strtolower(const string& s) {    // return the lowercase of the string
    string str = s;
    std::transform(str.begin(), str.end(), str.begin(), ::tolower);
    return str;
}
string strcapitalize (const string& s) {  // return the capitalisation (1 upper, rest lower) of the string
    string str = s;
    std::transform(str.begin(), str.end(), str.begin(), ::tolower);
    if (str.size() > 0)
        str[0] = toupper(str[0]); 
    return str;
}

然后是克隆单词大写的实用函数:它将形容词设置为小写或大写或将其大写(1个大写+其余小写)复制引用词的大小写。它足够强大,可以处理空词,以及不是字母数字的词:

string clone_capitalisation(const string& a, const string& w) {
    if (w.size() == 0 || !isalpha(w[0]))  // empty or not a letter
        return a;                         //   => use adj as it is
    else {
        if (islower(w[0]))   // lowercase
            return strtolower(a);
        else return w.size() == 1 || isupper(w[1]) ? strtoupper(a) : strcapitalize(a);
    }
}

所有这些函数都不会改变原始字符串!

现在到main():我不喜欢手动把所有可能的大写和小写组合的文章,所以我只工作大写。

我也不喜欢按顺序浏览每个单词的所有可能文章。如果有更多的文章,它不会很高效!所以我更喜欢使用&lt;set&gt;

...
set<string> articles  { "A", "AN", "THE" };   // shorter isn't it ? 
...
while (getline(rfile, line)) {
    istringstream iss(line);
    string word;
    while (iss >> word) {     // loop 
        cout << word << " ";  // output the word in any case
        if (articles.find(strtoupper(word))!=articles.end()) {  // article found ?
            if (iss >> word) {  // then read the next word
                cout << clone_capitalisation(adj, word) << " " << word << " ";
            }
            else cout << word;  // if case there is no next word on the line...
        }
    }
    cout << endl; 
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多