固定長データ
Posted feedbacks - Other
うーん。もうちょっとキレイに書けるかと思ったけど挫折した。。
あ、このお題、実用的でいいお題だなと思いました!
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 | module Doukaku170 =
struct
open System
open System.IO
type sex = F | M | U
type meal = { Morning : string;
Lunch : string;
Dinner : string }
type data = { LastName : string;
FirstName : string;
Sex : sex;
Age : int;
Year : int;
Month : int;
MealDays : (int * meal) list }
let get_datas file =
let (|Sex|) s = if s = "F" then F else if s = "M" then M else U in
let step_read n (r:#TextReader) =
let buffer = Array.zero_create n in
ignore (r.Read(buffer, 0, n));
String.trim [' '] (new string(buffer))
in
{ use r = new StreamReader(File.OpenRead(file)) in
while not r.EndOfStream do
yield { LastName = step_read 12 r;
FirstName = step_read 12 r;
Sex = (match step_read 1 r with Sex x -> x);
Age = Int32.Parse(step_read 3 r);
Year = Int32.Parse(step_read 4 r);
Month = Int32.Parse(step_read 2 r);
MealDays = [for _ in 1..31
-> (Int32.Parse(step_read 2 r),
{ Morning = step_read 500 r;
Lunch = step_read 500 r;
Dinner = step_read 500 r })] }
done }
end;;
let _ =
let datas = @"C:\test.txt" |> Doukaku170.get_datas |> Seq.to_list in
printf "%A\n" (List.hd datas);;
|
構造体はアライメントの対象になりますが、メンバが全てcharの場合は別です。
自分の理解不足に嘆いて、サンプルを作ってみました。
<結果>*VC2005で確認
sizeof A = 8
sizeof B = 5
sizeof C = 16
sizeof D = 16
sizeof E = 10
sizeof F = 24
いまいち釈然としなかったですが、参考ページの「配列にしたときにバイト境界をまたがないように、最小限のパディングが入れられる」という説明を読んでやっと納得できた気がします。
自分の理解不足に嘆いて、サンプルを作ってみました。
<結果>*VC2005で確認
sizeof A = 8
sizeof B = 5
sizeof C = 16
sizeof D = 16
sizeof E = 10
sizeof F = 24
いまいち釈然としなかったですが、参考ページの「配列にしたときにバイト境界をまたがないように、最小限のパディングが入れられる」という説明を読んでやっと納得できた気がします。
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 | #include <stdio.h>
struct A {
char c[2]; /* |c c| | */
int n; /* |n n n n| */
};
struct B {
char c[2]; /* |c c|d d| */
char d[3]; /* |d| | */
};
struct C { /* AとBの後ろに詰め物 */
struct A a;
struct B b;
};
struct D { /* AとBの後ろに詰め物 */
struct B b;
struct A a;
};
struct E { /* こいつは10バイトにみっちり詰まる */
struct B b1;
struct B b2;
};
struct F {
char c[3]; /* |c c c| | */
short s; /* |s s| | */
int n; /* |n n n n| */
short t; /* |t t|d d| */
char d[3]; /* |d| | */
char *p; /* |p p p p| */
};
int main(void) {
printf("sizeof A = %d\n", sizeof(struct A));
printf("sizeof B = %d\n", sizeof(struct B));
printf("sizeof C = %d\n", sizeof(struct C));
printf("sizeof D = %d\n", sizeof(struct D));
printf("sizeof E = %d\n", sizeof(struct E));
printf("sizeof F = %d\n", sizeof(struct F));
return 0;
}
|
sekiaさんのデータ作成スクリプトを使わせていただきました。
この結果を tmp.txtとして保存して準備しておきます。
see: テストデータ生成スクリプト (perl)
1 2 3 4 5 6 7 8 9 10 | a <- list();
nc <- c(12, 12, 1, 3, 4, 2, rep(c(2,500,500,500),31));
z <- file('tmp.txt', 'rb');
for(i in c(1:500)){
df <- readChar(z, nc);
a[[i]] <- df;
}
close(z);
a[[1]][c(1:10)];
|




Mymelo #6060() Rating5/7=0.71
固定長のデータが記載されたファイルを読み込むプログラムを作成してください。読み込んだデータは、複数の値を格納できるデータ型に格納してください。
ファイルには、すべて ascii 文字で以下のデータが格納されています。デリミタはなく、固定長で格納されています。レコードとレコードのあいだも改行はありません。
以上の形式のデータ500人分を読みこんで、データを複数の値を格納できるデータ型に格納してください。データに大して何か処理を行う必要はなく、すぐに破棄してかまいません。
この問題は、このようなファイルをどのように扱うかを知りたくて作成しました。
[ reply ]