textscan

2025-06-06

textscanは、Octave(およびMATLAB)において、テキストファイルや文字列から整形されたデータを読み込むための非常に強力で柔軟な関数です。主に、数値データや文字列が混在するような、規則的な構造を持つデータファイルを処理する際に威力を発揮します。

基本的な使い方

textscanの最も基本的な書式は以下の通りです。

C = textscan(FID, FORMAT)

または、文字列から読み込む場合:

C = textscan(STR, FORMAT)
  • FORMAT: データをどのように解釈するかを指定するフォーマット文字列。
  • STR: 読み込む対象の文字列。
  • FID: 読み込むテキストファイルへのファイル識別子(fopen関数で取得したもの)。

Cはセル配列として返され、フォーマット文字列で指定された各データタイプに対応する列が含まれます。

フォーマット文字列 (FORMAT)

フォーマット文字列は、C言語のscanf関数に似た形式で、読み込むデータの型を指定します。主なフォーマット指定子は以下の通りです。

  • %*...: 対応するデータを読み飛ばす(例: %*s は文字列を読み飛ばす)
  • %[...]: 指定された文字セット内の文字を読み込む(例: %[0-9] は数字のみ)
  • %q: ダブルクォーテーションで囲まれた文字列(クォーテーション自体は含まない)
  • %c: 単一文字
  • %s: 文字列(空白区切り)
  • %f または %g または %e: 浮動小数点数
  • %u: 符号なし整数
  • %d または %i: 符号付き整数

また、各フォーマット指定子には幅(フィールドの最大文字数)や、データタイプに応じて特定のオプションを追加できます。

例:

  • %s: 文字列
  • %f: 浮動小数点数
  • %5d: 最大5桁の整数

オプション引数

textscanは、さらに多くのオプション引数を取ることができます。これらは、データの読み込み方法を細かく制御するために使用されます。

C = textscan(FID, FORMAT, 'param', value, ...)

主なオプション引数:

  • 'ReadRows', NUM_ROWS:

    • 読み込む行数を制限します。
  • 'ReadChars', NUM_CHARS:

    • 読み込む文字数を制限します。
  • 'ReadBytes', NUM_BYTES:

    • 読み込むバイト数を制限します。
  • 'MultipleDelimitersAsOne', TRUE/FALSE:

    • TRUEの場合、連続する複数の区切り文字を1つの区切り文字として扱います。デフォルトはFALSEです。
  • 'ReturnOnError', TRUE/FALSE:

    • エラーが発生した場合にエラーを返すかどうかを指定します。TRUEの場合、エラー時に処理を中断します。デフォルトはFALSEです。
  • 'EndOfLine', EOL:

    • 行の終わりを示す文字を指定します。デフォルトはプラットフォームに依存します。
    • 例: 'EndOfLine', '\n'
  • 'EmptyValue', VAL:

    • 空の数値フィールドが見つかった場合に代入される値を指定します。デフォルトはNaNです。
    • 例: 'EmptyValue', 0
  • 'CommentStyle', STYLE:

    • コメント行のスタイルを指定します。指定された文字列で始まる行はコメントとして読み飛ばされます。
    • 例: 'CommentStyle', '%'%で始まる行はコメント)
    • 複数のスタイルを指定することも可能: 'CommentStyle', {'%', '//'}
  • 'HeaderLines', N:

    • ファイルの先頭からN行をヘッダーとして読み飛ばします。
    • 例: 'HeaderLines', 1 (最初の1行をスキップ)
  • 'WhiteSpace', WS:

    • 空白文字として扱う文字を指定します。デフォルトはスペース、タブ、改行、キャリッジリターンです。
    • 例: 'WhiteSpace', '' (空白文字を無視しない)
  • 'Delimiter', DELIM:

    • フィールドを区切る区切り文字を指定します。デフォルトはスペース、タブ、改行です。
    • 例: 'Delimiter', ',' (カンマ区切り)
    • 複数の区切り文字を指定することも可能: 'Delimiter', ',\t' (カンマまたはタブ)

使用例

例1: カンマ区切りのデータファイル

data.csvというファイルに以下の内容があるとします。

Name,Age,Score
Alice,30,85.5
Bob,24,92.0
Charlie,35,78.2

これを読み込むOctaveコード:

fid = fopen('data.csv', 'r');
C = textscan(fid, '%s%d%f', 'Delimiter', ',', 'HeaderLines', 1);
fclose(fid);

names = C{1};  % セル配列内の最初の要素(文字列)
ages = C{2};   % セル配列内の2番目の要素(整数)
scores = C{3}; % セル配列内の3番目の要素(浮動小数点数)

disp(names);
disp(ages);
disp(scores);

出力:

{"Alice"; "Bob"; "Charlie"}
30
24
35
85.500
92.000
78.200

例2: スペース区切りの数値データ(コメント行あり)

numbers.txtというファイルに以下の内容があるとします。

% This is a comment
10 20 30
40 50 60
# Another comment style
70 80 90
fid = fopen('numbers.txt', 'r');
C = textscan(fid, '%f %f %f', 'CommentStyle', {'%', '#'});
fclose(fid);

data_matrix = cell2mat(C); % セル配列を数値行列に変換

disp(data_matrix);
10   20   30
40   50   60
70   80   90

例3: 文字列から読み込む

str_data = 'Apple 1.23 True; Orange 4.56 False';
C = textscan(str_data, '%s %f %s', 'Delimiter', ';');

fruits = C{1};
values = C{2};
bools = C{3};

disp(fruits);
disp(values);
disp(bools);
{"Apple 1.23 True"; " Orange 4.56 False"}
{}(0x0)
{}(0x0)

注釈: 上記の例は、Delimiterがセミコロンで設定されているため、それぞれの要素が区切られて読み込まれます。しかし、%s %f %sというフォーマット指定子は、スペース区切りを前提としているため、期待する出力とは異なる結果になります。正しく読み込むには、Delimiterの設定を削除するか、フォーマット指定子を調整する必要があります。

正しい例:

str_data = 'Apple 1.23 True; Orange 4.56 False';
% 各行(セミコロンで区切られた部分)を個別に読み込む
line_data = textscan(str_data, '%s', 'Delimiter', ';');

fruits = {};
values = [];
bools = {};

for i = 1:numel(line_data{1})
    % 各行をさらにスペース区切りで解析
    part = textscan(line_data{1}{i}, '%s %f %s');
    fruits = [fruits; part{1}];
    values = [values; part{2}];
    bools = [bools; part{3}];
end

disp(fruits);
disp(values);
disp(bools);
{"Apple"; "Orange"}
1.2300
4.5600
{"True"; "False"}


フォーマット文字列とデータが一致しない

これが最もよくあるエラーです。ファイル内のデータの型や構造が、FORMAT文字列で指定した内容と一致しない場合に発生します。

エラーの例

  • 数値のフィールドに、余分な文字(通貨記号、単位など)が含まれている。
  • 日付や時刻のフォーマットが期待通りでない。
  • 期待される数値データがあるフィールドに、数値ではない文字列(例: "N/A", "Unknown")がある。

トラブルシューティング

  • 'ReturnOnError', false の使用
    デフォルトでは、textscanはフォーマット不一致が発生した場合にエラーを返して停止します。このオプションをfalseに設定すると、エラーを無視してできる限りデータを読み込み続け、問題のあるフィールドは空の値(数値ならNaN、文字列なら空のセル)で埋められます。これにより、どこで問題が発生しているかを確認しやすくなります。
  • データタイプの不一致
    • 数値が期待される場所に文字列がある場合:
      • その文字列を読み飛ばすために%*sを使用するか、
      • 'TreatAsEmpty'オプションを使って特定の文字列を空の値(NaNなど)として扱うように指定します。ただし、'TreatAsEmpty'は数値型(%fなど)にのみ適用され、%d(整数)ではエラーになる可能性があります。
      • 最も安全なのは、そのフィールドを一旦%sで文字列として読み込み、後でOctaveの文字列操作関数やstr2doubleなどを使って数値に変換し、エラー処理を行うことです。
    • 整数(%d)を読み込もうとしているが、浮動小数点数(例: 3.14)や空のフィールド(NA)がある場合:
      • フォーマット指定子を%fに変更することを検討してください。浮動小数点数型は、整数も空の値もより柔軟に扱えます。
  • FORMAT文字列の確認
    ファイル内の実際のデータと、%d, %f, %s などのフォーマット指定子が正確に一致しているか確認してください。

区切り文字 (Delimiter) の不一致

データが期待通りの区切り文字で区切られていない場合に発生します。

エラーの例

  • 区切り文字が連続しているが、'MultipleDelimitersAsOne'を設定し忘れている。
  • 複数の種類の区切り文字が混在している(例: カンマとセミコロン)。
  • タブ区切りのファイルを読み込むのに、スペース区切りとして扱っている。
  • CSV(カンマ区切り)ファイルを読み込むのに、'Delimiter', ',' を指定し忘れている。

トラブルシューティング

  • 空白文字
    デフォルトでは、textscanは空白文字(スペース、タブ、改行など)を区切り文字として扱います。特定の区切り文字のみを使用し、空白文字を無視したい場合は、'WhiteSpace', '' を設定し、'Delimiter'で明示的に区切り文字を指定します。
  • 連続する区切り文字
    連続する区切り文字を1つの区切り文字として扱う場合は、'MultipleDelimitersAsOne', true を設定します。
  • 'Delimiter' オプションの確認
    ファイルで使用されている区切り文字(カンマ、タブ、スペース、セミコロンなど)を正確に指定します。複数の区切り文字がある場合は、セル配列で指定できます(例: 'Delimiter', {',', ';', '\t'})。

ヘッダー行やコメント行の処理

データファイルの先頭にヘッダー行やコメント行があるにもかかわらず、それらを適切にスキップしていない場合に、データがずれたり、読み込みエラーになったりします。

エラーの例

  • コメント行がデータの一部として解釈されてしまう。
  • ヘッダー行がデータとして読み込まれてしまい、型の不一致エラーが発生する。

トラブルシューティング

  • 'CommentStyle', STYLE の使用
    コメント行の開始文字や文字列を正確に指定します。複数のコメントスタイルがある場合は、セル配列で指定できます(例: 'CommentStyle', {'%', '#'})。
  • 'HeaderLines', N の使用
    データが始まる前にスキップすべきヘッダー行の数Nを正確に指定します。

ファイルパスまたはファイル識別子 (FID) の問題

ファイルが存在しない、パスが間違っている、またはfopenが正しく実行されていない場合に発生します。

エラーの例

  • fopen-1を返す(ファイルが開けなかったことを示す)。
  • "Invalid file identifier" や "File not found" のようなエラー。

トラブルシューティング

  • fclose(fid) の呼び忘れ
    ファイルを開いた後は、必ずfclose(fid)でファイルを閉じるようにしてください。これを怠ると、ファイルがロックされたり、リソースがリークしたりする可能性があります。
  • ファイルアクセス権
    ファイルに対する読み取り権限があるか確認します。
  • fopenの戻り値の確認
    fid = fopen('filename', 'r') の後で、if fid == -1 のようにして、ファイルが正常に開かれたかを確認する習慣をつけましょう。
  • カレントディレクトリの確認
    Octaveが実行されているカレントディレクトリにファイルがあるか、または完全なパスを指定しているか確認します。
  • ファイルパスの確認
    ファイル名とパスが正しいことを確認します。

出力形式の誤解 (textscanはセル配列を返す)

textscanの出力が常にセル配列であるということを理解していない場合に、データの扱いで混乱が生じることがあります。

エラーの例

  • 全てのデータが同じ型であるにも関わらず、結果をそのまま行列として扱おうとする。
  • C{1} のようにセル配列から要素を取り出すことをせずに、直接 C(1) のようにアクセスしようとする。

トラブルシューティング

  • データへのアクセス
    • 特定の列のデータにアクセスするには、C{index}のように中括弧{}を使用します。
    • 全てのデータが数値型であれば、cell2mat(C) を使ってセル配列を数値行列に変換できます。
    • 異なる型のデータが混在している場合は、それぞれを個別に抽出して処理する必要があります。
  • 出力はセル配列
    textscanは常にセル配列を返します。各フォーマット指定子に対応するデータが、セル配列の各要素として格納されます。

空のフィールド(数値)

数値が期待されるフィールドが空である場合、デフォルトではNaNが挿入されますが、これを別の値にしたい場合があります。

エラーの例

  • 空の数値フィールドがNaNとして扱われるのが不都合な場合。

トラブルシューティング

  • 'EmptyValue', VAL の使用
    空の数値フィールドに挿入される値を指定できます。例えば、'EmptyValue', 0 とすると、空のフィールドは0として扱われます。

パフォーマンスの問題(大きなファイル)

非常に大きなファイルをtextscanで読み込む場合、メモリ使用量や処理時間が問題になることがあります。

  • 代替関数の検討
    非常に単純なCSVファイルであれば、csvreaddlmreadの方がシンプルで高速な場合があります。ただし、これらの関数はtextscanほどの柔軟性はありません。
  • 必要最低限のデータの読み込み
    不要な列は%*を使って読み飛ばすことで、メモリと処理時間を節約できます。
  • チャンク読み込み
    ファイル全体を一度に読み込むのではなく、'ReadRows', 'ReadBytes', 'ReadChars' オプションを使って、少しずつ(チャンク単位で)読み込むことを検討します。これにより、メモリ消費を抑えられます。


例1: CSV (カンマ区切り) ファイルの読み込み

最も一般的な使用例の一つです。数値と文字列が混在するCSVファイルを読み込みます。

data.csv の内容

Name,Age,Score
Alice,30,85.5
Bob,24,92.0
Charlie,35,78.2
David,40,90.0

Octave コード

% 1. ファイルを開く
filename = 'data.csv';
fid = fopen(filename, 'r');

% ファイルが開けなかった場合のチェック
if fid == -1
    error('ファイルを開けませんでした: %s', filename);
end

% 2. フォーマット文字列とオプションの指定
% %s: 文字列 (Name)
% %d: 整数 (Age)
% %f: 浮動小数点数 (Score)
% 'Delimiter', ',': 区切り文字をカンマに指定
% 'HeaderLines', 1: 最初の1行(ヘッダー行)をスキップ
formatSpec = '%s%d%f';
options = {'Delimiter', ',', 'HeaderLines', 1};

% 3. textscan でデータを読み込む
C = textscan(fid, formatSpec, options{:});

% 4. ファイルを閉じる
fclose(fid);

% 5. 読み込んだデータへのアクセス
names = C{1};  % 1列目 (Name) はセル配列
ages = C{2};   % 2列目 (Age) は数値配列
scores = C{3}; % 3列目 (Score) は数値配列

% 結果の表示
disp('名前:');
disp(names);
disp('年齢:');
disp(ages);
disp('スコア:');
disp(scores);

% 必要であれば、数値データを結合して行列にする
numerical_data = [ages, scores];
disp('年齢とスコアの行列:');
disp(numerical_data);

解説

  • cell2mat を使って、数値データが格納されたセル配列を通常の行列に変換できます(ただし、全ての要素が同じ数値型である必要があります)。
  • textscan は結果をセル配列 C として返します。各列は C{1}, C{2} のようにアクセスできます。
  • 'HeaderLines', 1 で最初のヘッダー行をスキップします。
  • 'Delimiter', ',' でカンマが区切り文字であることを指定します。
  • formatSpec で各列のデータ型を定義します。%sは文字列、%dは整数、%fは浮動小数点数です。
  • fopen(filename, 'r') でファイルを読み取りモードで開きます。fid はファイル識別子です。

例2: スペース区切りのデータとコメント行のスキップ

データがスペースで区切られており、特定の文字で始まる行をコメントとして無視する例です。

measurements.txt の内容

# This is a comment about the data below.
# Date: 2023-01-15
Measurement_ID  Value  Unit
101             15.2   kg
102             23.8   m
103             9.1    s

Octave コード

filename = 'measurements.txt';
fid = fopen(filename, 'r');

if fid == -1
    error('ファイルを開けませんでした: %s', filename);
end

% フォーマット文字列とオプションの指定
% %d: Measurement_ID
% %f: Value
% %s: Unit
% 'CommentStyle', '#': '#'で始まる行をコメントとしてスキップ
% 'HeaderLines', 1: 'Measurement_ID Value Unit' の行をスキップ
formatSpec = '%d%f%s';
options = {'CommentStyle', '#', 'HeaderLines', 1};

C = textscan(fid, formatSpec, options{:});

fclose(fid);

ids = C{1};
values = C{2};
units = C{3};

disp('測定ID:');
disp(ids);
disp('値:');
disp(values);
disp('単位:');
disp(units);

解説

  • スペース区切りはtextscanのデフォルトの区切り文字なので、'Delimiter'を指定する必要はありません。
  • ヘッダー行もスキップするために'HeaderLines', 1 を使います。
  • 'CommentStyle', '#' を指定することで、#で始まる行が自動的にスキップされます。

例3: 空のフィールドの処理と連続する区切り文字

データに空のフィールドがあり、それを特定の値で埋めたい場合や、複数の連続する区切り文字を1つとして扱いたい場合の例です。

sales_data.txt の内容

ProductA,,120.5,50
ProductB,150,
ProductC,200,90.2,75
ProductD,,

Octave コード

filename = 'sales_data.txt';
fid = fopen(filename, 'r');

if fid == -1
    error('ファイルを開けませんでした: %s', filename);
end

% フォーマット文字列とオプションの指定
% %s: Product Name
% %d: Quantity (空の場合がある)
% %f: Price (空の場合がある)
% %d: Stock (空の場合がある)
% 'Delimiter', ',': 区切り文字をカンマに指定
% 'EmptyValue', -1: 空の数値フィールドを -1 で埋める
% 'MultipleDelimitersAsOne', true: 連続するカンマを1つの区切り文字として扱う
formatSpec = '%s%d%f%d';
options = {'Delimiter', ',', 'EmptyValue', -1, 'MultipleDelimitersAsOne', true};

C = textscan(fid, formatSpec, options{:});

fclose(fid);

products = C{1};
quantities = C{2};
prices = C{3};
stock = C{4};

disp('製品:');
disp(products);
disp('数量:');
disp(quantities);
disp('価格:');
disp(prices);
disp('在庫:');
disp(stock);

解説

  • 'MultipleDelimitersAsOne', true は、例えば ,, のように連続するカンマを1つの区切り文字として扱います。これにより、空のフィールドの処理が容易になります。
  • 'EmptyValue', -1 を使用すると、数値フィールドが空の場合に -1 が代入されます。デフォルトでは NaN(Not a Number)が使われます。

例4: 特定の行数を読み込む / 残りをスキップ

ファイル全体ではなく、最初の数行だけを読み込みたい場合や、特定のデータブロックだけを読み込みたい場合に便利です。

log.txt の内容

Log Start: 2024-01-01 08:00:00
INFO: System initialized.
DATA: 10.5 20.1 30.7
DEBUG: Internal process running.
DATA: 11.2 22.5 33.1
INFO: Operation complete.
DATA: 12.8 24.0 36.5

Octave コード

filename = 'log.txt';
fid = fopen(filename, 'r');

if fid == -1
    error('ファイルを開けませんでした: %s', filename);
end

% 最初の2行をスキップ
textscan(fid, '%*[^\n]', 2); % 2行分の内容を読み飛ばす

% 次の 'DATA:' で始まる行を読み込む
% '%s': 'DATA:' を読み込む
% '%f %f %f': 3つの浮動小数点数を読み込む
% 'Delimiter', ':': コロンを区切り文字として使用
formatSpec = '%s %f%f%f';
options = {'Delimiter', ':', 'CollectOutput', true}; % CollectOutput で数値をまとめて行列にする

C_data = textscan(fid, formatSpec, 1, options{:}); % 1行だけ読み込む

fclose(fid);

label = C_data{1};
values = C_data{2}; % CollectOutput=true により、数値は行列として返される

disp('データラベル:');
disp(label);
disp('データ値:');
disp(values);
  • その後、目的の DATA: 行を textscan で読み込みます。
  • textscan(fid, '%*[^\n]', 2): この行は、ファイルの最初の2行を読み飛ばすために使用されます。
    • %*: 読み飛ばすことを意味します。
    • [^\n]: 改行文字以外の全ての文字を意味します。
    • 2: 2回繰り返す(つまり2行読み飛ばす)ことを意味します。


textscanは汎用的なテキスト解析に優れていますが、特定の種類のデータや、よりシンプルなファイル形式の場合には、以下のような代替関数やアプローチが役立ちます。

csvread および dlmread (数値データ専用)

これらの関数は、区切り文字で区切られた数値データのみを含むファイルを読み込むのに最適です。textscanよりもシンプルに書けるため、手軽に数値ファイルを処理したい場合に便利です。

  • dlmread(filename, delimiter): 指定された区切り文字(delimiter)で区切られた数値データファイルを読み込み、行列として返します。
  • csvread(filename): カンマ区切りの数値データファイルを読み込み、行列として返します。

利点

  • 結果が直接数値行列として返されるため、追加の変換が不要。
  • 非常にシンプルで使いやすい。

欠点

  • 大きなファイルではtextscanに比べて性能が劣る場合がある。
  • 柔軟性に欠ける: ヘッダー行のスキップやコメント行の処理は限定的です(csvreaddlmreadには引数として行・列のオフセットを指定できますが、textscan'HeaderLines''CommentStyle'のような柔軟性はありません)。
  • 数値データのみ対応
    文字列や混在するデータ型は扱えません。

使用例
data_num.csvというファイルに以下の内容があるとします。

10,20,30
40,50,60
70,80,90
% csvread を使用
data_csv = csvread('data_num.csv');
disp('csvreadの結果:');
disp(data_csv);

% dlmread を使用 (カンマ区切り)
data_dlm_comma = dlmread('data_num.csv', ',');
disp('dlmread(カンマ区切り)の結果:');
disp(data_dlm_comma);

% dlmread を使用 (スペース区切り) - 例えば、スペース区切りファイルの場合
% 仮に 'data_space.txt' が '1 2 3\n4 5 6' のような内容の場合
% data_dlm_space = dlmread('data_space.txt', ' ');
% disp('dlmread(スペース区切り)の結果:');
% disp(data_dlm_space);

load (ASCIIデータファイル用)

load関数は、スペース区切りの数値データのみを含むシンプルなASCIIファイルを読み込むのに使用できます。変数を保存したMATファイルも読み込めますが、テキストファイルに対しても機能します。

利点

  • 結果が直接変数として読み込まれる。
  • 非常にシンプル。

欠点

  • ヘッダーやコメントのスキップはできない。
  • スペース区切りの数値データのみ
    フォーマットの柔軟性が最も低い。

使用例
simple_data.txtというファイルに以下の内容があるとします。

1 2 3
4 5 6
7 8 9
% load を使用
data_load = load('simple_data.txt');
disp('loadの結果:');
disp(data_load);

fgetl または fgets と文字列処理 (strsplit, sscanf, 正規表現など)

より複雑な、あるいは不規則なフォーマットのテキストファイルを扱う場合、ファイルを行ごとに読み込み(fgetlfgets)、その後Octaveの文字列処理関数を使って各行を解析するというアプローチが非常に強力です。これは、textscanのオプションだけでは対応しきれないような特殊なケースで特に有効です。

fgetl(FID): ファイルから1行を読み込み、改行文字を含まない文字列として返します。 fgets(FID): ファイルから1行を読み込み、改行文字を含む文字列として返します。

利点

  • 行ごとの処理なので、メモリ効率が良い場合がある。
  • エラー処理や条件分岐をコード内で細かく制御できる。
  • 最高の柔軟性
    任意の複雑なファイル形式に対応できます。

欠点

  • 大規模なファイルでは、textscancsvread/dlmreadよりも処理が遅くなる可能性がある。
  • 単純なケースでは冗長になる。
  • プログラミングの手間がかかる。

使用例
log_complex.txtというファイルに以下の内容があるとします。

# Log entry created on 2024-01-01
EVENT: Startup complete. User: admin
DATA: Temp=25.3C; Humidity=60.1%; Pressure=1012hPa
# End of day log
EVENT: Shutdown initiated.
DATA: Temp=20.1C; Humidity=65.5%; Pressure=1008hPa
filename = 'log_complex.txt';
fid = fopen(filename, 'r');

if fid == -1
    error('ファイルを開けませんでした: %s', filename);
end

events = {};
temperatures = [];
humidities = [];
pressures = [];

while ~feof(fid) % ファイルの終端までループ
    line = fgetl(fid); % 1行読み込む

    if ischar(line) % 正常に読み込めたか確認 (EOFの場合は-1が返るため)
        % コメント行をスキップ
        if startsWith(line, '#')
            continue;
        end

        % 'EVENT:' で始まる行を処理
        if startsWith(line, 'EVENT:')
            event_msg = strtrim(line(7:end)); % 'EVENT:' 以降の文字列を抽出
            events = [events; event_msg];

        % 'DATA:' で始まる行を処理
        elseif startsWith(line, 'DATA:')
            data_str = strtrim(line(6:end)); % 'DATA:' 以降の文字列を抽出
            
            % セミコロンで分割
            parts = strsplit(data_str, ';');
            
            % 各部分を解析
            temp_str = strtrim(parts{1}); % 例: "Temp=25.3C"
            humid_str = strtrim(parts{2}); % 例: "Humidity=60.1%"
            pressure_str = strtrim(parts{3}); % 例: "Pressure=1012hPa"
            
            % 数値を抽出
            temp_val = sscanf(temp_str, 'Temp=%fC');
            humid_val = sscanf(humid_str, 'Humidity=%f%%'); % '%' はエスケープが必要
            pressure_val = sscanf(pressure_str, 'Pressure=%fhPa');

            temperatures = [temperatures; temp_val];
            humidities = [humidities; humid_val];
            pressures = [pressures; pressure_val];
        end
    end
end

fclose(fid);

disp('イベントメッセージ:');
disp(events);
disp('温度:');
disp(temperatures);
disp('湿度:');
disp(humidities);
disp('気圧:');
disp(pressures);

解説

  • sscanf() を使って、特定のフォーマット(例: Temp=%fC)から数値を抽出します。正規表現(regexpregexprep)もこのような抽出に非常に役立ちます。
  • strsplit() で区切り文字(この例ではセミコロン)を使って文字列を分割します。
  • strtrim() で文字列の前後の空白を削除します。
  • startsWith() を使って行の先頭の文字列をチェックし、コメント行やデータ行の種類を判別します。
  • fgetl(fid) で1行ずつ読み込みます。
  • while ~feof(fid) でファイルの終端までループします。

高度なパッケージ (例: ioパッケージ)

Octaveには、特定のファイル形式を扱うための追加パッケージが存在する場合があります。例えば、ioパッケージは、より多くのファイル形式(例: Excelファイル、NetCDFなど)をサポートする関数を提供することがあります。これは、textscanの範囲を超えた、特定のバイナリ形式や構造化データ形式を扱う場合に検討する価値があります。

インストール
pkg install -forge io ロード: pkg load io

利点

  • バイナリファイルやより複雑なデータ構造に対応できる。
  • 特定のファイル形式に最適化されている。
  • すべてのOctave環境で利用できるとは限らない。
  • 外部パッケージのインストールが必要。

どの方法を選ぶべきか?

  • 特定のファイル形式
    Excelファイルや他の標準化されたバイナリデータ形式を扱う場合は、関連するOctaveパッケージを検討します。
  • 不規則な形式や高度な解析
    textscanでは対応しきれないほど複雑なフォーマットや、行ごとに異なる処理が必要な場合は、fgetl/fgetsと文字列処理関数を組み合わせるアプローチが最適です。
  • シンプルな数値データ
    数値データのみで、ヘッダーやコメントが少ない場合は、csvreaddlmreadが最もシンプルで高速です。
  • 最も一般的な推奨
    まずはtextscanを試すべきです。ほとんどの構造化されたテキストファイルに対して、強力かつ柔軟な解決策を提供します。