MATLAB Textscan格式复杂性与后处理

时间:2014-02-27 01:44:33

标签: matlab text-processing textscan

我对MATLAB的textscan有疑问。我有一个非常多的列的文件,以及1-32行(与#col相比非常小)的文件。这是一个简单的例子:

Test1 1 2 3 4 5
Test2 6 7 8 9 10

提前知道列数,提前知道第一个且唯一开始一行的字符串的长度。我在第一行读取并计算列数,并构建实际格式字符串以在文件的其余部分中读取,如下所示:

function output = parseFile(filename) 

%% Calculate Number of Samples
% Reads in first line
tic
fid = fopen(filename);
line = fgetl(fid);
fclose(fid);
firstLine = textscan(line, '%s', 'CollectOutput', true);
numSamples = size(firstLine{1},1) - 1;
toc

%% Parse File
tic
fid = fopen(filename);
format = ['%s ' repmat('%f', [1 numSamples]) '%*[^\n\r]'];
fileData = textscan(fid, format, 'CollectOutput', true);
fclose(fid);
 toc

%% Format Output
output.names = cell2mat(fileData{1});
output.values = fileData{2};


end     % end function

我选了几个例子,每次我得到以下内容:说我有一个包含100,000列和3行的文件。 tic / toc告诉我第一行读取在.16秒内完成。然后,当我构建格式字符串并读取整个文档时,它将在9秒内完成。为什么第一行作为%s读入时如此快速地读取,但下次我读取整个文件(仅多+2行)时需要更长时间?是因为更复杂的format字符串,我第二次解析文件?将整个文件解析为空格分隔的字符串然后执行后处理(例如:str2double)以获得我的双打矩阵是否有意义?

编辑:澄清文件格式的具体细节:

(string of unknown length)(1 space)(-123.001)(1 space)(41.341)(1 space)...
...

所以数字 int,而且它们是正面/负面的。

注意:我实际上很困惑的是,为什么textscan能够非常快速地读取文件的第一行,而接下来的两行比第一行长

1 个答案:

答案 0 :(得分:1)

将字符串转换为数字的常用技巧是从字符串中删除double('0')。此外,这种方式比str2double快得多。例如,运行此代码:

% Using -double('0')
tic, for i=1:1e5;  aux='9'-48;      end, toc
% Using str2double()
tic, for i=1:1e5;  str2double('9'); end, toc
% Using str2num()
tic, for i=1:1e5;  str2num('9');    end, toc

我明白了:

Elapsed time is 0.000480 seconds.
Elapsed time is 2.445741 seconds.
Elapsed time is 2.524999 seconds.

因此,你可以构造一个解析每一行的函数(我猜这个函数可以更优化):

function num = parseText(str)
    strCell = strsplit(str,' ');
    strNum = cellfun(@(s) s-48, strCell(2:end),'UniformOutput', false);
    nNum = numel(strNum);  num = zeros(1,nNum);
    for idxNum=1:nNum, 
        num(idxNum) = strNum{idxNum}*10.^(length(strNum{idxNum})-1:-1:0).'; 
    end
end

如果您尝试一行,结果很好:

str = 'Test1 0 1 2 3 4 5 10';
num = parseText(str);

如果您尝试多行,它似乎也很好:

% Create text
L = 10;   str = cell(L,1);
for idx1=1:L, 
    strAux = []; for idx2=1:randi(10),  strAux = [strAux,' ',num2str(randi(10))];  end
    str{idx1} = ['Test',num2str(idx1),strAux];
end

% Parse text
num = cell(L,1);
for idx=1:L, 
    num{idx} = parseText(str{idx});
end