challenge 固定長データ

固定長のデータが記載されたファイルを読み込むプログラムを作成してください。読み込んだデータは、複数の値を格納できるデータ型に格納してください。

ファイルには、すべて ascii 文字で以下のデータが格納されています。デリミタはなく、固定長で格納されています。レコードとレコードのあいだも改行はありません。

  1. 姓 (12文字) 文字数が足りない場合は、後ろを空白で埋めてあります。
  2. 名 (12文字) 文字数が足りない場合は、後ろを空白で埋めてあります。
  3. 性別 (F,M,Uの3種類、1文字)
  4. 年齢 (3桁の数字、桁数が足りない場合は、ゼロで埋めず、頭を空白で埋めてあります。
  5. 年 2008 固定
  6. 月 03 固定
  7. さらに以下のデータが日付分くりかえされます。
    1. 日付 (01 〜 31) 2文字
    2. 朝食のメニュー (500文字)
    3. 昼食のメニュー (500文字)
    4. 夕食のメニュー (500文字)

以上の形式のデータ500人分を読みこんで、データを複数の値を格納できるデータ型に格納してください。データに大して何か処理を行う必要はなく、すぐに破棄してかまいません。

この問題は、このようなファイルをどのように扱うかを知りたくて作成しました。

Posted feedbacks - C++

メモリ上の構造≠ファイル上の構造の前提で書きました。 予想以上にstreamの扱いに苦戦。streamと固定長データは相性が良くない…というより、わたしがstreamを使い切れていないというのが正解かも。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <iterator>

struct Menu
{
    std::string date;
    std::string breakfast;
    std::string lunch;
    std::string dinner;
};

typedef std::vector<Menu> Menus;

struct Record
{
public:
    std::string lastName;
    std::string firstName;
    std::string sex;
    std::string age;
    std::string year;
    std::string month;
    Menus       menus;
};

std::istream& operator >> (std::istream& in, Menu& menu)
{
    char s[500];
    in.read(s, 2);   menu.date      = std::string(s, 2);
    in.read(s, 500); menu.breakfast = std::string(s, 500);
    in.read(s, 500); menu.lunch     = std::string(s, 500);
    in.read(s, 500); menu.dinner    = std::string(s, 500);

    return in;
}

std::istream& operator >> (std::istream& in, Record& record)
{
    char s[500];
    in.read(s, 12); record.lastName  = std::string(s, 12);
    in.read(s, 12); record.firstName = std::string(s, 12);
    in.read(s,  1); record.sex       = std::string(s,  1);
    in.read(s,  3); record.age       = std::string(s,  3);
    in.read(s,  4); record.year      = std::string(s,  4);
    in.read(s,  2); record.month     = std::string(s,  2);

    std::istream_iterator<Menu> itr(in);
    for(int i = 0; i < 31; ++i)
    {
        record.menus.push_back(*itr++);
    }

    return in;
}

#include <fstream>

void read(const std::string& filename, std::vector<Record>& records)
{
    records.clear();

    std::ifstream source(filename.c_str(), std::ios::binary);

    std::istream_iterator<Record> itr(source);
    for(int i = 0; i < 500; ++i)
    {
        records.push_back(*itr++);
    }
}

// 以下はテストデータを作成するためのコードです。

std::ostream& operator << (std::ostream& out, const Menu& menu)
{
    std::ios::fmtflags flags = out.flags();
    out.setf(std::ios::left);
    out << std::setw(2)   << menu.date;
    out << std::setw(500) << menu.breakfast;
    out << std::setw(500) << menu.lunch;
    out << std::setw(500) << menu.dinner;
    out.flags(flags);

    return out;
}

std::ostream& operator << (std::ostream& out, const Record& record)
{
    std::ios::fmtflags flags = out.flags();
    out.setf(std::ios::left);
    out << std::setw(12) << record.lastName;
    out << std::setw(12) << record.firstName;
    out << std::setw(1)  << record.sex;
    out << std::setw(3)  << record.age;
    out << std::setw(4)  << record.year;
    out << std::setw(2)  << record.month;
    out.flags(flags);

    for(int i = 0; i < 31; ++i)
    {
        out << record.menus[i];
    }

    return out;
}

#include <sstream>

std::string toString(int value, int col)
{
    std::stringstream s;
    s << std::setfill('0') << std::setw(col) << value;
    return s.str();
}

void write(const std::string& filename)
{
    Record record;

    record.lastName  = "LASTNAME";
    record.firstName = "Firstname";
    record.sex       = "U";
    record.age       = " 99";
    record.year      = "2008";
    record.month     = "03";

    Menu menu;

    menu.breakfast = "breakfast";
    menu.lunch     = "lunch";
    menu.dinner    = "dinner";

    for(int i = 0; i < 31; ++i)
    {
        menu.date = toString(i + 1, 2);
        record.menus.push_back(menu);
    }

    std::ofstream file(filename.c_str(), std::ios::binary);

    for(int i = 0; i < 500; ++i)
    {
        file << record;
    }
}

Index

Feed

Other

Link

Pathtraq

loading...