std :: out_of_range, генерируемый при разборе текстового файла - PullRequest
0 голосов
/ 18 октября 2011

У меня есть следующий код для чтения текстового файла.

const string FILENAME = PACKAGES_DIR + pname;
  //the arguments to ifstream is a cstring and hence the conversion must be made
  ifstream freader;
  freader.open(FILENAME.c_str(),ios::in);
  if(freader.is_open())
  {
    while(freader.good())
    {
      string line;
      getline(freader,line);
      cout<<line<<endl;
      if(line.find("PackageId:"))
      {
        cout<<line.substr(11)<<endl;
      }
      else if(line.find("Name:"))
      {
        cout<<line.substr(5)<<endl;
      }
      else if(line.find("Version:"))
      {
        cout<<line.find(8)<<endl;
      }
      else
      {
        cout<<line<<endl;
      }

    }
  }

Содержимое рассматриваемого текстового файла:

PackageId:994
Name:basket
Version:1.80-1
Deps:kdebase-runtime,libc0.1,libc0.1-udeb,libc6,libc6-udeb,libc6.1,libc6.1-udeb,libgcc1,libgpg-error0,libgpgme11,libkdecore5,libkdeui5,libkfile4,libkio5,libkparts4,libkutils4,libphonon4,libqimageblitz4,libqt4-dbus,libqt4-network,libqt4-qt3support,libqt4-svg,libqt4-xml,libqtcore4,libqtgui4,libstdc++6,libunwind7,libx11-6,phonon

Вывод, который я получаю, -

PackageId:994
geId:994
Name:basket

Version:1.80-1
0-1
Deps:kdebase-runtime,libc0.1,libc0.1-udeb,libc6,libc6-udeb,libc6.1,libc6.1-udeb,libgcc1,libgpg-error0,libgpgme11,libkdecore5,libkdeui5,libkfile4,libkio5,libkparts4,libkutils4,libphonon4,libqimageblitz4,libqt4-dbus,libqt4-network,libqt4-qt3support,libqt4-svg,libqt4-xml,libqtcore4,libqtgui4,libstdc++6,libunwind7,libx11-6,phonon
e-runtime,libc0.1,libc0.1-udeb,libc6,libc6-udeb,libc6.1,libc6.1-udeb,libgcc1,libgpg-error0,libgpgme11,libkdecore5,libkdeui5,libkfile4,libkio5,libkparts4,libkutils4,libphonon4,libqimageblitz4,libqt4-dbus,libqt4-network,libqt4-qt3support,libqt4-svg,libqt4-xml,libqtcore4,libqtgui4,libstdc++6,libunwind7,libx11-6,phonon

terminate called after throwing an instance of 'std::out_of_range'
  what():  basic_string::substr

Вывод, который я хотел получить:

PackageId:994
994
Name:basket
basket
Version:1.80-1
1.80-1
...

Что я сделал не так?

Ответы [ 5 ]

5 голосов
/ 18 октября 2011

Задача 1

while .good или while !.eof - это почти всегда неправильно . Выбросьте любую книгу, которая говорила вам сделать это, и сделайте это вместо .

В этом случае измененный код выглядит примерно так:

const string FILENAME = PACKAGES_DIR + pname;
//the arguments to ifstream is a cstring and hence the conversion must be made
ifstream freader(FILENAME.c_str(), ios::in);
if (freader) {
   string line;
   while (getline(freader,line)) {  // <-----
      cout << line << endl;

      if (line.find("PackageId:"))
         cout << line.substr(11) << endl;
      else if (line.find("Name:"))
         cout << line.substr(5) << endl;
      else if (line.find("Version:"))
         cout << line.find(8) << endl;
      else
         cout << line << endl;
   }
}

Задача 2

Вы неправильно используете std::string::find.

line.find("PackageId:") возвращает либо «позицию первого вхождения в строке искомого содержимого», либо значение элемента npos, если совпадение не найдено.

Это в сочетании с не выполнением проверки границ для первого параметра std::string::substr вызывает проблемы с вашими строками.

Вместо этого напишите:

if (line.find("PackageId:") != std::string::npos)

Задача 3

cout<<line.find(8)<<endl; должен сказать substr, а не find.


Ваш код с некоторыми из выше исправленных:

const string FILENAME = PACKAGES_DIR + pname;
//the arguments to ifstream is a cstring and hence the conversion must be made
ifstream freader(FILENAME.c_str(), ios::in);
if (freader) {
   string line;
   while (getline(freader,line)) {  // <-----
      cout << line << endl;

      if (line.find("PackageId:")    != std::string::npos && line.size() > 11)
         cout << line.substr(11) << endl;
      else if (line.find("Name:")    != std::string::npos && line.size() > 5)
         cout << line.substr(5) << endl;
      else if (line.find("Version:") != std::string::npos && line.size() > 8)
         cout << line.substr(8) << endl;
      else
         cout << line << endl;
   }
}
2 голосов
/ 18 октября 2011

Проверьте сгенерированное исключение, оно ясно скажет вам, что не так.
what() исключения выдает:

что (): basic_string :: substr

Это говорит вам,
Исключение составляет substr

См. Документацию string :: substr :

string substr ( size_t pos = 0, size_t n = npos ) const;

Создать подстроку

Возвращает строковый объект с его содержимым, инициализированным подстрокой текущего объекта.

Эта подстрока представляет собой последовательность символов, которая начинается с символа позиция pos и имеет длину n символов.

Параметры

  • pos Положение символа в текущем строковом объекте, который будет использоваться в качестве начального символа подстроки Если пройденная позиция находится за концом строки, генерируется исключение out_of_range.

  • n Длина подстроки. Если это значение заставит подстроку простираться после конца текущего содержимого строки, только эти символы до конца строки используются. npos это постоянное значение статического члена с максимально возможным значением для элемент типа size_t, поэтому, когда это значение используется, все символы между положением и концом строки используются как подстрока инициализации.

1 голос
/ 18 октября 2011

Первая проблема, которая выпадает, состоит в том, что вы пытаетесь прочитать строку и использовать эту строку, не проверяя, успешно ли чтение.Вместо того, чтобы проверить, хорош ли файл в состоянии while, вы должны изменить свой цикл на что-то вроде этого:

string line;
while(getline(freader,line))
{
    // now you can safely process line
}
1 голос
/ 18 октября 2011

Изменить

      else if(line.find("Version:"))
      {
        cout<<line.find(8)<<endl; //<--------------------
      }

На

      else if(line.find("Version:"))
      {
        cout<<line.substr(8)<<endl; //<----------------------
      }
0 голосов
/ 18 октября 2011

Вместо использования фиксированных констант для позиций substr используйте переменную позиции:

std::string::size_t  position = 0;
static const char packageIdFieldName[] = "PackageId:";
position = find(packageIdFieldName);
if (position != std::string::npos)
{
    // The "sizeof('\0')" is a blantant reminder to subract
    //    the size of the terminating nul character.
    cout << line.substr(position + sizeof(packageIdFieldName) - sizeof('\0'))
         << endl;
    continue;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...