可能有一种方法可以一次性完成,但对我来说,使用 2 遍方法更容易对这类问题进行排序。
- 第 1 遍:根据类型(字符串、整数等)读取所有具有常量格式的列,并在单独的列中读取非常量部分,该列将在第二遍中处理。
- 通过 2:根据其特殊性处理不规则列。
在您的示例数据中,它看起来像这样:
%% // read file
fid = fopen('Test.txt','r') ;
M = textscan( fid , 'term%d %s %*c %[^]] %*[^\n]' ) ;
fclose(fid) ;
%% // dispatch data into variables
name = M{1,1} ;
time = M{1,2} ;
data = cellfun( @(s) textscan(s,'%f',Inf,'Delimiter',',') , M{1,3} ) ;
发生了什么:
第一条textscan 指令读取整个文件。在格式说明符中:
-
term%d 在文字表达式 'term' 之后读取 整数。
-
%s 读取代表日期的字符串。
-
%*c忽略一个字符(忽略字符'[')。
-
%[^]] 读取所有内容(作为字符串),直到找到字符']'。
-
%*[^\n] 忽略所有内容,直到下一个换行符 ('\n') 字符。 (不捕获最后一个']'。
之后,前 2 列很容易被分派到它们自己的变量中。结果元胞数组M 的第 3 列包含不同长度的字符串,其中包含不同数量的浮点数。我们使用cellfun 结合另一个textscan 来读取每个单元格中的数字并返回一个包含double 的单元格数组:
奖金:
如果您希望您的时间也是一个数值(而不是字符串),请使用以下代码扩展:
%% // read file
fid = fopen('Test.txt','r') ;
M = textscan( fid , 'term%d %f-%f-%f-%f_%f_%f_%f %*c %[^]] %*[^\n]' ) ;
fclose(fid) ;
%% // dispatch data
name = M{1,1} ;
time_vec = cell2mat( M(1,2:7) ) ;
time_ms = M{1,8} ./ (24*3600*1000) ; %// take care of the millisecond separatly as they are not handled by "datenum"
time = datenum( time_vec ) + time_ms ;
data = cellfun( @(s) textscan(s,'%f',Inf,'Delimiter',',') , M{1,end} ) ;
这将为您提供一个数组time,其中包含一个 Matlab 时间序列号(通常比字符串更易于使用)。给你看序列号还是代表正确的时间:
>> datestr(time,'yyyy-mm-dd HH:MM:SS.FFF')
ans =
2015-07-31 15:58:25.612
2015-07-31 15:58:25.620
2015-07-31 15:58:25.625