将字符串和整数从文本文件输入到变量中

时间:2013-04-30 14:28:47

标签: c++ file-io

嘿,有可能有一个文本文件,其内容是:

Weapon Name: Katana
Damage: 20
Weight: 6

是否可以将这些信息分配到武器类的成员变量中? 所以,当我在我的主要调用getWeaponName时,我会得到Katana吗?

我正在寻找谷歌,我可以获得整个文本文件输入,但它没有分配给任何变量。

我到目前为止的代码是:

Weapons :: Weapons()
{
    this->weaponName = "";
    this->damage = 0;
    this->weight = 0;
}

Weapons :: Weapons(string weaponName,int damage,int weight)
{
    this->weaponName = weaponName;
    this->damage = damage;
    this->weight = weight;
}

void Weapons ::  getWeapon()
{
    ifstream myfile ("Weapons\\Katana.txt");
    string line;
    if (myfile.is_open())
    {
        while (myfile.good())
        {
            getline (myfile,weaponName,'\t');//This line gets the entire text file.
            //getline (myfile,damage,'\t');
            //getline (myfile,weight,'\t');
            //myfile >> weaponName;
            //myfile >> damage;
            //myfile >> weight;
            cout << weaponName<< "\n";
        }
        myfile.close();
    }

    else
    {
        cout << "Unable to open file";
    }
}

提前致谢。

4 个答案:

答案 0 :(得分:2)

更改

getline (myfile, weaponName, '\t');

getline (myfile, weaponName);

你的版本正在做的是告诉getline抓取文件中的所有内容,直到制表符,我猜你没有任何制表符。我推荐的版本 - 没有指定分隔符 - 将使字符达到换行符。所以它应该在Weapon Name: Katana中阅读。

然后你还需要提取“Katana”。假设您的输入文件具有非常固定的格式,您可以简单地执行类似

的操作
weaponName = weaponName.substr(weaponName.find_first_of(':') + 2);

这将从':'之后的位置2开始子串。

修改

使用weaponName并不完全适合您的getline语句。 weaponName是一个字符串,但在那时,你只是在找一条线。您已在getWeapon()中拥有适当的变量。我们只需要使用它们:

void Weapons ::  getWeapon()
{
    ifstream myfile ("Weapons\\Katana.txt");
    string line;
    string number;
    if (myfile.is_open())
    {
        while (myfile.good())
        {
            getline (myfile,line);
            weaponName = line.substr(line.find_first_of(':') + 2);
            getline (myfile,line);
            number = line.substr(line.find_first_of(':') + 2);
            damage = atoi(number.c_str());
            getline (myfile,line);
            number = line.substr(line.find_first_of(':') + 2);
            weight = atoi(number.c_str()); 
            cout << weaponName<< "\n";
        }
        myfile.close();
    }
    else
    {
        cout << "Unable to open file";
    }
 }

注意:您需要#include <stdlib.h> atoi才能工作。

老实说,这仍然不是很强大。其他人为您提供了更好的解决方案,用于查看输入以查看数据是什么,以及读取和存储所有数据,但这应该向您展示非常基础。

答案 1 :(得分:2)

您需要解析文件的每一行。所以,改变功能

getline(myfile, weaponName, '\t');

getline(myfile, weaponName);

并解析结果。

做类似的事情:

#include <cstdio>
#include <string>

using namespace std;

int main() 
{
  string line = "Weapon Name: Katana";

  int pos = line.find(':');
  string weaponName;
  if ( line.substr(0, pos) == "Weapon Name")
    weaponName = line.substr(pos+1, line.npos);

  printf("%s\n", weaponName.c_str());
}

答案 2 :(得分:1)

首先,你需要/想要区分“武器”(复数)和单一武器。为了更有意义,每个武器都具有您正在阅读的特征(名称,重量,伤害)。因此,武器将是各个武器对象的集合,每个武器对象都具有这些特征。

基于此,我们可以尝试编写一些有意义的代码:

class weapon {
    std::string name;
    int damage;
    int weight;
public:
    std::string get_name() { return name; }

现在,我们希望weapon能够从存储在文件中的数据中“重构”自己。但是请注意,现在我们正在写一个weapon类,所以我们只会处理一个武器,而不是它们的整个集合:

friend std::istream &operator>>(std::istream &is, weapon &w) { 
    std::ignore(is, 1024, ':'); // ignore the "Weapon Name:" header
    std::getline(is, w.name);
    std::ignore(is, 1024, ':'); // ignore the "Damage:" header
    is >> w.damage;
    std::ignore(is, 1024, ':');  // ignore the "Weight:" header
    is >> w.weight;
    return is;
}

虽然我们还不需要它,但是让我们创建一个匹配函数来写出正确格式的武器:

std::ostream &operator<<(std::ostream &os, weapon const &w) { 
   return os << "Weapon Name: " << w.name << "\n"
             << "Damage: " << w.damage << "\n"
             << "Weight: " << w.weight << "\n";
}

有了这个,我们可以读取单一武器的数据。然后我们需要一些方法来存储多种武器。由于缺乏理由,我们的第一选择通常是std::vector。如果我们想用文件中的数据填充它,我们可以这样做:

// open a file of all the weapons data:
std::ifstream in("weapons.txt");

// initialize the vector from the data in the file:
std::vector<weapon> weapons((std::istream_iterator<weapon>(in)),
                             std::istream_iterator<weapon>());

有了这个,我们可以(例如)列出所有武器(这里我们将使用上面定义的“operator&lt;&lt;”):

 std::copy(weapons.begin(), weapons.end(), 
           std::ostream_iterator<weapon>(std::cout, "\n"));

如果我们想要一个只包含每种武器名称的缩略列表,我们可以这样做:

for (auto const &w : weapons)
    std::cout << w.get_name() << "\n";

答案 3 :(得分:0)

您的格式看起来像是典型.ini文件的变体。那里 如果可以修改,那么周围有很多解析器 格式使其符合。到目前为止,这是最简单的 解。否则:各种武器是如何分开的 文件?它是一个空行,还是因为第一个 条目总是"Weapon Name"?在第一种情况下,我会使用 像下面这样的东西来阅读文件(免费的 功能,而不是成员):

std::auto_ptr<Weapon> currentWeapon;
Line line;
int lineNumber = 0;
while ( source >> line ) {
    ++ lineNumber;
    if ( line.empty() ) {
        if ( currentWeapon.get() != NULL ) {
            weaponCollection.insert( currentWeapon );
        }
        currentWeapon.release();
    } else {
        Line::const_iterator pivot 
            = std::find( line.begin(), line.end(), ':' );
        if ( pivot == line.end() ) {
            //  Output error message, using lineNumber...
        } else {
            if ( currentWeapon.get() == NULL ) {
                currentWeapon.reset( new Weapon );
            }
            std::string key( strip( std::string( line.begin(), pivot ) ) );
            std::string value( strip( std::string( pivot + 1, line.end() ) ) );
            if ( key == "WeaponName" ) {
                currentWeapon->weaponName = value;
            } else if ( key == "Damage" ) {
                currentWeapon->damage = asInt( value );
            } else if ( key == "Weight" ) {
                currentWeapon->weight = asInt( value );
            } // ...
            else {
                // output error message...
            }
        }
    }
}

Line是我工具箱中的一个类,我在此类中使用了很多 事情基本上是这样的:

class Line : private std::string
{
public:
    typedef std::string::iterator iterator;
    //  ...
    using std::string::empty;
    using std::string::begin;
    //  ...
};

它与std::string之间的唯一区别在于它 operator>>调用std::getline,然后“清理”结果, 通过删除任何尾随空格(包括可能的 '\r',因为该文件是在Windows下编写的,但我是 在Unix下阅读它);在这种情况下,它可能是有用的 它还删除任何领先的空白区域。 (我也有 设置注释字符的操纵器;如果设置了它,它 从该字符中删除任何文本到行尾, 在修剪尾随空格之前。 (根据经验:确实提供某种评论工具 在文件中。如果你不这样做,你会后悔的。)

asInt当然是:

int
asInt( std::string const& original )
{
    std::istringstream s( original );
    int results;
    s >> results >> std::ws;
    if ( !s || s.get() != EOF ) {
        //  Error...
    }
    return results;
}

同样,你的工具箱中应该有的东西。

如果新武器的钥匙是"Weapon Name"属性, 跳过空行业务(或将空行视为注释), 并存储任何现有武器并在中创建新武器 处理"Weapon Name"

如果你在上面犯了错误,你需要使用try ... catch 阻止输出错误并继续。你可能也想 标记某处出现错误,并在游戏中止 如此。