2013-04-24 11 views
5

Ho problemi a leggere da un file di input. Il file di input appare cosìLettura dal file di input

Lionel Messi -10 43

Fernando Torres 9 -29

Cristiano Ronaldo 7 31

Wayne Rooney 10 37

Neymar 17 29

Andres Iniesta 8 32

Robin van Persie 19 20

Lionel Messi 10 43

Xavi 6 36

Mesut Özil 10 38

Didier Drogba 10 35

Fernando Torres 9 29

Kaká 10 17

Il problema è che non posso usare la funzione getline perché voglio memorizzare il nome in una singola variabile da memorizzare in una matrice, e il primo numero in una variabile e il secondo in un'altra variabile. Ho anche provato a usare la funzione Peek ma non l'ho mai imparato, quindi non ho avuto successo con esso. Se qualcuno sa come leggere fino alla fine del nome e memorizzarlo in una singola variabile sarebbe molto apprezzato.

Questo è ciò che il mio codice è simile quando im lettura dal file di input

while(!fin.eof()) 
    { 

    fin >> first >> last >> num >> point; 

    if (num > 0 && point > 0) 
    { 
      list[i].firstname = first; 
      list[i].lastname = last; 
      list[i].number = num; 
      list[i].points = point; 
      i++; 
    } 
    else if (num < 0 || point < 0) 
    { 
      reject[j].firstname = first; 
      reject[j].lastname = last; 
      reject[j].number = num; 
      reject[j].points = point; 
      j++; 
    } 

    } 

Questo funziona perfettamente se l'ingresso ha un primo e un cognome. So che il problema è su pinna >> prima >> ultima >> num >> punto;

ma io non sono esattamente sicuro di come mettere prima e l'ultima (e possibilmente al centro) insieme

+4

Ah, ma è possibile utilizzare 'getline'. – chris

+1

Lo "spazio" tra le parti dei nomi è lo stesso di quello tra l'ultimo nome e i numeri? Sarebbe di grande aiuto se fosse un carattere tab '\ t'' tra l'ultimo dei nomi e i numeri. Altrimenti, (probabilmente) vorrete leggere un'intera riga e quindi rimuovere i bit numerici dal retro della stringa (usando 'std :: string :: find_last_of' e' std :: string :: substr' per esempio) –

+0

Sì, tutti gli spazi sono gli stessi tra i nomi e i numeri. Quindi è possibile memorizzare l'intera linea in una variabile stringa, quindi rimuovere i due numeri dalla fine della stringa e inserirli in variabili separate? – kylekolossus

risposta

0

In realtà, è possibile utilizzare getline(); Usa il metodo dei due parametri, passandogli un flusso e '\ n' come delimitatore.

Assegnare l'intera linea in una stringa, quindi dividere la stringa utilizzando uno spazio come delimitatore e nascondere i secondi due in numeri interi.

+0

Spazio non disponibile negli spazi in nome (che è variabile per nome) –

+0

Risposta aggiornata all'indirizzo. –

+0

@MichaelDorgan È ancora possibile in questo modo ... basta usare gli ultimi due elementi come interi e tutti gli altri elementi (non importa quanti) come nome. Dato che c'è una quantità fissa di numeri interi dopo ogni nome. –

4

È possibile utilizzare std::getline per estrarre le righe, l'analisi della linea in un std::vector di parole separate dallo spazio. Allora sai che le parole words.size() - 2 fanno parte del nome. Per esempio:

std::fstream in("in.txt"); 
std::string line; 

// Extract each line from the file 
while (std::getline(in, line)) { 
    std::istringstream line_stream(line); 

    // Now parse line_stream into a vector of words 
    std::vector<std::string> words(std::istream_iterator<std::string>(line_stream), 
           (std::istream_iterator<std::string>())); 

    int name_word_count = words.size() - 2; 
    if (name_word_count > 0) { 
    // Concatenate the first name_word_count words into a name string 
    // and parse the last two words as integers 
    } 
} 
+0

Questa non è una brutta soluzione. Non avevo considerato il fatto che '>>' in una stringa utilizza lo spazio bianco come separatore. (Naturalmente, come hai scritto, non verrà compilato, ma non sarai il primo a cadere nell'analisi più imbarazzante. Avvia uno (o entrambi) gli argomenti al costruttore di 'words' con un altro gruppo di parentesi: –

+0

@JamesKanze Hm, mi chiedo perché stia succedendo. Sicuramente il primo argomento non può essere un tipo (ha 'line_stream' in esso)? –

+0

' line_stream' sarà interpretato come Nome del primo parametro –

0

1.) Aprire il file

std::ifstream myFile("somewhere.txt"); 

2.) Verificare se il file è aperto

if(myFile.is_open()) 

3.) Leggi fino alla fine del file di

while(!myFile.eof()) 

4.) Leggere il primo nome in un primo nome di matrice

myFile >> firstName[numberOfPeople]; 

5.) Leggi l'ultimo nome nella cognome serie

myFile >> lastName[numberOfPeople]; 

6.) Leggere il numero intero in un array intero

myFile >> integer[numberOfPeople]; 

7.) Aumento del numero di persone

numberOfPeople++; 

8.) Quando, mentre è fatto, chiudere il file

myFile.close(); 

9.) Se non si è aperta il file, segnalare l'errore.

else 
    std::cout << "\nFile did not open. " << std::endl; 

È possibile utilizzare la funzione getline, è sufficiente analizzare la stringa. Questo può essere ottenuto usando strtok.

+2

Non si vuole mai usare 'strtok'. –

+0

E non hai davvero bisogno della chiusura. (Lo fai per l'output, perché devi controllare che abbia successo, ma per l'input, non lo fai.) –

+2

E ri "codice cattivo in questo thread": 'while (! MyFile.eof())' è decisamente un errore e codice pessimo. –

1

Mi sembra che sia necessario utilizzare getline e quindi analizzare la riga . Una soluzione per l'analisi potrebbe essere quella di dividere la riga poco prima della prima cifra, quindi tagliare la prima metà e utilizzarla per il nome e analizzare la seconda metà utilizzando std::istringstream per leggere i due numeri. Ciò non riuscirà, ovviamente, se qualcuno ha una cifra come parte del loro nome, ma che mi sembra un limite legittimo. In altre parole, per ogni linea, faresti:

std::string::iterator first_digit 
     = std::find_if(line.begin(), line.end(), IsDigit()); 
if (first_digit == line.end()) { 
    // format error... 
} else { 
    name = trim(std::string(line.begin(), first_digit)); 
    std::istringstream parser(std::string(first_digit, line.end())); 
    parser >> firstNumber >> secondNumber >> std::ws; 
    if (!parser || parser.get() != EOF) { 
     // format error... 
    } else { 
     // Do what ya gotta do. 
    } 
} 
1

Qualcosa del genere dovrebbe funzionare:

std::string str; 
while(getline(infile, str)) 
{ 
    std::string::size_type pos; 
    pos = str.find_last_of(' '); 
    if (pos == std::string::npos || pos < 1) 
    { 
     cout << "Something not right with this string: " << str << endl; 
     exit(1); 
    } 
    int last_number = stoi(str.substr(pos)); 
    str = str.substr(0, pos-1); // Remove the number and the space. 
    pos = str.find_last_of(' '); 
    if (pos == std::string::npos || pos < 1) 
    { 
     cout << "Something not right with this string: " << str << endl; 
     exit(1); 
    } 
    int first_number = stoi(str.substr(pos)); 
    str = str.substr(0, pos-1); 
    // str now contains the "name" as one string. 

    // ... here you use last_number and first_number and str to do what you need to do. 
} 
0

Ho implementato una soluzione al vostro problema (soprattutto per il mio apprendimento). Funziona come previsto, ma sembra un po 'lungo.

#include<string> 
#include<fstream> 
#include<sstream> 
#include<iostream> 
#include<vector> 
#include<algorithm> 
#include<iterator> 

struct PlayerData { 
    std::string name; 
    int number; 
    int points; 
}; 

std::ostream& operator<<(std::ostream& os, const PlayerData& p) { 
    os<<"Name: "<<p.name<<", Number: "<<p.number<<", Points: "<<p.points; 
    return os; 
} 

PlayerData parse(const std::string& line) { 
    PlayerData data; 
    std::stringstream ss(line); 
    std::vector<std::string> tokens; 
    std::copy(std::istream_iterator<std::string>(ss), 
      std::istream_iterator<std::string>(), 
      std::back_inserter<std::vector<std::string>>(tokens)); 
    data.points = std::stoi(tokens.at(tokens.size() - 1)); 
    data.number = std::stoi(tokens.at(tokens.size() - 2)); 
    for(auto it=tokens.begin(); it!=tokens.end()-2; ++it) { 
    data.name.append(" "); 
    data.name.append(*it); 
    } 
    return data; 
} 

int main(int argc, char* argv[]) { 
    std::string line; 
    std::vector<PlayerData> players; 

    { // scope for fp          
    std::ifstream fp(argv[1], std::ios::in); 
    while(!fp.eof()) { 
     std::getline(fp, line); 
     if(line.size()>0) { 
     players.push_back(parse(line)); 
     } 
    } 
    } // end of scope for fp 

    // print list of players, or do whatever you want with it. 
    for(auto p:players) { 
    std::cout<<p<<std::endl;  
    } 

    return 0; 
} 

Compilare con una versione di g ++ che supporta C++ 11 (nel mio caso gcc 4.7.2).

[Prompt] g++ -oparseline parseline.cpp -std=c++11 -O2 
[Prompt] ./parseline players.txt 
Name: Fernando Torres, Number: 9, Points: -29 
Name: Cristiano Ronaldo, Number: 7, Points: 31 
Name: Wayne Rooney, Number: 10, Points: 37 
Name: Neymar, Number: 17, Points: 29 
Name: Andres Iniesta, Number: 8, Points: 32 
Name: Robin van Persie, Number: 19, Points: 20 
Name: Lionel Messi, Number: 10, Points: 43 
Name: Xavi Hernandez, Number: 6, Points: 36 
Name: Mesut Özil, Number: 10, Points: 38 
Name: Didier Drogba, Number: 10, Points: 35 
Name: Fernando Torres, Number: 9, Points: 29 
Name: Kaká, Number: 10, Points: 17 
Problemi correlati