嘿,有可能有一个文本文件,其内容是:
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";
}
}
提前致谢。
答案 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 阻止输出错误并继续。你可能也想 标记某处出现错误,并在游戏中止 如此。