0

ちょっと、その内容が次のテキストファイルを持つことは可能ですか:

Weapon Name: Katana
Damage: 20
Weight: 6

これらの情報を武器クラスのメンバー変数に割り当てることは可能ですか?. メインで getWeaponName を呼び出すと、カタナが取得されますか?

私はグーグルを見回していましたが、テキストファイル全体の入力を取得できますが、どの変数にも割り当てられていません。

私がこれまでに持っているコードは次のとおりです。

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

4 に答える 4

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());
}
于 2013-04-30T14:52:08.567 に答える
2

変化する

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

getline (myfile, weaponName);

あなたのバージョンがやっていることはgetline、タブ文字まで、ファイル内のすべてを取得するように指示していることです.タブ文字はないと思います. 私が推奨しているバージョン (区切り文字を指定しない) では、改行までの文字が取得されます。したがって、 を読み込む必要がありますWeapon Name: Katana

次に、「Katana」を抽出する必要があります。入力ファイルの形式が非常に固定されていると仮定すると、次のような単純なことができます

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

これは、「:」の後の位置 2 から始まる部分文字列を取ります。

編集

getline ステートメントの使用weaponNameは正確には適切ではありません。 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>動作するにはforが必要ですatoi

正直なところ、これはまだそれほど堅牢ではありません。他の人は、入力を見てデータが何であるかを確認し、すべてのデータを読み取って保存するためのより良いソリューションを提供していますが、これは非常に基本的なことを示しているはずです。

于 2013-04-30T14:46:15.120 に答える
1

まず、「武器」(複数形)と単一の武器を区別する必要があります。わかりやすいように、個々の武器にはそれぞれの特徴 (名前、重量、ダメージ) があります。したがって、武器は個々の武器オブジェクトのコレクションになり、それぞれが特性を持ちます。

それに基づいて、意味のあるコードを書くことができます。

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

ここで、weaponがファイルに格納されたデータから自身を「再構成」できるようにしたいと考えています。ただし、現在はクラスを作成しているため、武器のコレクション全体ではなく、1 つの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 に答える