Почему istream::getline() возвращает так много раз (ничего)

Я пытаюсь прочитать плохо отформатированный текстовый файл, и, возможно, я делаю это неправильно, но, основываясь на документации getline, это звучало так, как будто он будет извлекать значения до тех пор, пока значения не будут значением разделителя (' ', в мое дело):

"Если разделитель найден, он извлекается и отбрасывается, т.е. не сохраняется и после него начнется следующая операция ввода. Если вы не хотите, чтобы этот символ извлекался, вы можете использовать вместо него member get."

Но по какой-то причине он ничего не возвращает много раз. Смотрите строки 604-607, все эти запятые в моем выводе — это возврат getline. Может ли кто-нибудь сказать мне, почему он возвращает пробелы 6 раз, прежде чем доходит до значения? Текстовый файл содержит только один пробел перед значением. Заранее спасибо. :)

Соответствующий скриншот: http://j.drhu.me/2011-09-07_1317.png< /а>

#include <iostream>
#include <fstream>
#include <string>
void CMuscleModel::LoadOpParams()
{
int i, j;

ifstream param("params.txt", ios::in);
        if (param.is_open())
        {
            stringstream iss, isn;
            string line, word;

            i=0; j=0;
            while (getline(param,line))
            {
                isn.clear();
                isn << line;
                if(i>27){
                    while (getline(isn,word,' ')) {
                        //LGma[i][j]=atof(word.c_str());
                        if(word == "SM"){
                            getline(param,line);
                            cout << line << endl << endl;

                            isn.clear(); isn << line;

                            getline(isn,word,' ');

                            int junk=0;
                            while (atof(word.c_str())==0){
                                junk++;
                                getline(isn,word,' ');
                            }

                            cout << atof(word.c_str()) << ", " << junk << endl;
                        }
                        if(word == "ST"){
                            cout << word << endl;
                        }
                        if(word == "BFL"){
                            cout << word << endl;
                        }
                        if(word == "BFS"){
                            cout << word << endl;
                        }
                        if(word == "MG"){
                            cout << word << endl;
                        }
                        if(word == "LG"){
                            cout << word << endl;
                        }
                        if(word == "RF"){
                            cout << word << endl;
                        }
                        if(word == "VM"){
                            cout << word << endl;
                        }
                        if(word == "VL"){
                            cout << word << endl;
                        }
                        if(word == "VI"){
                            cout << word << endl;
                        }
                        j++;
                    }
                }
                j=0; i++;
                isn.clear();
            }
        }
        param.close();
}

Ах, извините, что не включил код.


person DonaldH    schedule 07.09.2011    source источник
comment
Пожалуйста, включите минимальный пример компилируемого кода, демонстрирующий проблему, с которой вы столкнулись в тексте вашего вопроса.   -  person CB Bailey    schedule 07.09.2011
comment
Что такое isn? Я подозреваю, что вы пишете в него isn << line;, а затем считывается следующая строка кода getline(isn,word,' ');   -  person Mooing Duck    schedule 07.09.2011
comment
Кроме того, возможно ли, что за строкой ввода перед (SM) следовала табуляция, преобразованная в пять пробелов?   -  person Mooing Duck    schedule 07.09.2011
comment
Можете ли вы сократить свою опубликованную программу до полного, минимального, компилируемого примера, включая краткий ввод, а также ожидаемый и фактический вывод? Объяснение того, почему это важно, см. на странице sscce.org.   -  person Robᵩ    schedule 07.09.2011


Ответы (3)


Если вы используете пробел в качестве разделителя каждый раз, когда он встречается, getline вернет все, что было до разделителя. Например, если в файле было 5 пробелов подряд перед любыми другими символами, вам пришлось бы вызывать getline 6 раз.

Возможно, вместо '\n' использовать символ новой строки по умолчанию?

Изменить: не видел кода раньше. Возможно, реструктурируйте свой код так, чтобы он читал строки, а затем использовал find в сочетании с substr в каждой строке для поиска ваших ключевых слов? Был бы более простой код и меньше циклов. Нет причин читать из файла только для вывода в поток строк, из которого вы затем читаете.

person AJG85    schedule 07.09.2011
comment
Вот почему я в замешательстве. Перед значением, которое я хотел поймать, был только 1 пробел. - person DonaldH; 07.09.2011
comment
ошибки, конец файла и т. д. также могут привести к завершению извлечения и возврату getline. - person AJG85; 07.09.2011

Двунаправленный ввод-вывод с std::stringstream действительно неоднозначен. Я рекомендую вам использовать его немного по-другому.

ifstream param("params.txt", ios::in);
if (param.is_open())
{
    stringstream iss;
    string line, word;
    i=0; j=0;
    while (getline(param,line))
    {
        istringstream isn(line);
        // ...
    }
}

Это создает новый поток строк с чистым состоянием и содержит содержимое строки, считываемой из файла каждый раз. Если вы действительно хотите повторно использовать экземпляр для чтения токенов в нескольких строках, я рекомендую вам использовать синтаксис .str(line), а не .clear() и operator<<.

Если вы хотите очистить пробел в начале каждой строки, вы можете использовать манипулятор std::ws :

istringstream isn(line);
isn >> ws;
// ...
person André Caron    schedule 07.09.2011

Я думаю, что в выходном текстовом файле, который я читал, были конечные пробелы, и они просто помещались в поток, поэтому я действительно был сбит с толку тем, что происходит. Я просто использовал .str("") в конце каждой строки, чтобы сбросить мой текущий поток, и все сработало чудесно. Спасибо за всю помощь, ребята.

person DonaldH    schedule 16.09.2011