0

Hey is it possible to have a text file which its contents are:

Weapon Name: Katana
Damage: 20
Weight: 6

Is it possible to assign these bits of information into member variables of a weapons class?. So that when i call getWeaponName in my main i will get Katana?

I was looking around google and i can get the whole text file input but its not assigned to any variable.

The code i have so far is:

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

Thanks in advance.

4

4 回答 4

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>foratoi才能工作。

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

于 2013-04-30T14:46:15.120 回答
2

You will need to parse each line of your file. So, change the function

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

to

getline(myfile, weaponName);

and parse result.

Do something like that:

#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());
}
于 2013-04-30T14:52:08.567 回答
1

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

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

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

现在,我们希望 aweapon能够从存储在文件中的数据“重构”自身。但是请注意,现在我们正在编写一个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<<”):

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

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

for (auto const &w : weapons)
    std::cout << w.get_name() << "\n";
于 2013-04-30T14:52:44.393 回答
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 块来输出错误并继续。您可能还想标记某处存在错误,如果是,则中止游戏。

于 2013-04-30T15:07:58.460 回答