解析文本文件时抛出std :: out_of_range

nik*_*hil 0 c++ file-io text

我有以下代码来读取文本文件.

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

    }
  }
Run Code Online (Sandbox Code Playgroud)

有问题的文本文件的内容是

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
Run Code Online (Sandbox Code Playgroud)

我得到的输出是

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
Run Code Online (Sandbox Code Playgroud)

我想要的输出是:

PackageId:994
994
Name:basket
basket
Version:1.80-1
1.80-1
...
Run Code Online (Sandbox Code Playgroud)

我做错了什么?

Lig*_*ica 5

问题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;
   }
}
Run Code Online (Sandbox Code Playgroud)

问题2

你没有std::string::find正确使用.

line.find("PackageId:")返回"搜索内容的字符串中第一次出现的位置",npos如果未找到匹配则返回成员值.

这与未对第一个参数执行边界检查相结合std::string::substr会导致字符串出现问题.

相反,写:

if (line.find("PackageId:") != std::string::npos)
Run Code Online (Sandbox Code Playgroud)

问题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;
   }
}
Run Code Online (Sandbox Code Playgroud)