2015-02-13 4 views
0

Im очень новичок в C++ и ive долгое время пытались выяснить, как это сделать. В принципе, мне нужно прочитать из файла и найти все экземпляры статьи («a», «A», «an», «aN», «an», «AN», «the», «The», «Это», «Это», «Это», «ТЭ», «ТЭ», «А»), а затем вставить прилагательное после этой статьи. Капитализация прилагательного должна основываться на слове, первоначально представленном перед статьей. Например, если бы я нашел «SHARK», мне нужно было бы сделать его «HAPPY SHARK». Может ли кто-нибудь сказать мне, что лучший способ сделать это? До сих пор я слом много идей, и это то, что я есть сейчас, хотя я не думаю, что я могу сделать это таким образом:C++ ищет строку из файла для определенных слов, а затем вставляя слово после этих слов

#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; 
       } 
      } 
     } 
     } 
    } 
+0

Не зацикливайтесь на '.good()', но на 'getline()'. Это потоковый цикл цикла до конца файла! – Christophe

+0

ok плохое изменение, спасибо – illusiate

ответ

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, я не уверен.) Во всяком случае, с помощью ввода/вывода может выглядеть примерно так:

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; 
     } 
    } 
} 

Возможно, вы хотите вывести остальную часть ввода тоже?

+0

К сожалению, мне нужно обрабатывать статью в конце строки .., а также если файл заканчивается статьей, у него не должно быть вставлено после него. есть ли лучший способ поиска по файлу? – illusiate

+0

Да, я просто разместил его :) – jschultz410

+0

Что делать, если я сделал что-то вроде этого? rfile.open (file.c_str()); if (rfile.fail()) { cerr << "Ошибка при попытке открыть файл." << endl; return 0; } string nextToken; while (rfile >> nextToken) { // cout << nextToken << endl; for (int i = 0; i <= 14; i ++) { if (nextToken == articles [i]) { // cout << nextToken + "" << endl; } } } rfile.close(); return 0; – illusiate

0

Сначала я предлагаю вам использовать 3 вспомогательные функции для преобразования строк. Это будет полезно, если вы много работаете с текстом. Здесь они основаны на <algorithm> но 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 + верхняя отдыха ниже) копирование случая слово refernce. Это достаточно прочным, чтобы обрабатывать пустые слова, а слова Wich не alaphanumeric:

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(): Мне не нравится вручную устанавливать все возможные комбинации верхних и нижних регистров статей, поэтому я работаю только в верхнем регистре.

Мне не нравится либо последовательно просматривать все возможные статьи для каждого слова. Если будет еще много статей, это будет не очень хорошо! Поэтому я предпочитаю использовать <set>:

... 
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; 
}