textscan
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ファイルであれば、csvread
やdlmread
の方がシンプルで高速な場合があります。ただし、これらの関数は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
に比べて性能が劣る場合がある。 - 柔軟性に欠ける: ヘッダー行のスキップやコメント行の処理は限定的です(
csvread
やdlmread
には引数として行・列のオフセットを指定できますが、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, 正規表現など)
より複雑な、あるいは不規則なフォーマットのテキストファイルを扱う場合、ファイルを行ごとに読み込み(fgetl
やfgets
)、その後Octaveの文字列処理関数を使って各行を解析するというアプローチが非常に強力です。これは、textscan
のオプションだけでは対応しきれないような特殊なケースで特に有効です。
fgetl(FID)
: ファイルから1行を読み込み、改行文字を含まない文字列として返します。
fgets(FID)
: ファイルから1行を読み込み、改行文字を含む文字列として返します。
利点
- 行ごとの処理なので、メモリ効率が良い場合がある。
- エラー処理や条件分岐をコード内で細かく制御できる。
- 最高の柔軟性
任意の複雑なファイル形式に対応できます。
欠点
- 大規模なファイルでは、
textscan
やcsvread
/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
)から数値を抽出します。正規表現(regexp
やregexprep
)もこのような抽出に非常に役立ちます。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
と文字列処理関数を組み合わせるアプローチが最適です。 - シンプルな数値データ
数値データのみで、ヘッダーやコメントが少ない場合は、csvread
やdlmread
が最もシンプルで高速です。 - 最も一般的な推奨
まずはtextscan
を試すべきです。ほとんどの構造化されたテキストファイルに対して、強力かつ柔軟な解決策を提供します。