Reading parameters from a text file into the workspace

故事扮演 提交于 2019-12-04 18:19:20

The quick-and-dirty approach

The simplest solution I could think of to read this file indeed employs textscan :) and since the lines are conveniently written in valid MATLAB syntax, you could use eval later to evaluate them. Start by reading each line as one string (ignoring the comments in the header)

fid = fopen(filename);
C = textscan(fid, '%s', 'Delimiter', '', 'CommentStyle', '%')
fclose(fid);

Then feed the lines one by one into eval to create the variables in the MATLAB workspace:

cellfun(@eval, C{1});

What this does is interpret the line as a MATLAB command, i.e create variables as named in the file and assign the appropriate values. If you want to suppress the output of eval, you can use evalc instead to "absorb the output":

cellfun(@evalc, C{1}, 'UniformOutput', false);

This should work for your basic example, but it would fail if you have more than one instance of any parameter. Also note that the eval family is notoriously slow.

A more robust approach

If the lines in your file structure have the parameter name = number pattern, you can read the lines more intelligently:

fid = fopen(filename);
C = textscan(fid, '%[^= ]%*[= ]%f', 'CommentStyle', '%')
fclose(fid);

The %[^= ] in the pattern matches the first characters until the first space or equality sign. The %*[ =] ignores the equality sign and any trailing spaces, and then the numerical value is matched with %f. The resulting cell array C stores the parameter names in the first cell and their corresponding values in the second cell.

Now it's up to you to manipulate the parsed data. For instance, to extract all values of lat and lon, you can do this:

lat = C{2}(strcmp(C{1}, 'lat'));
lon = C{2}(strcmp(C{1}, 'lon'));

If you have more than one "lat" line, lat will be an array holding all these values.

Here's another quick and dirty way:

fp = fopen('foo.txt');

found = 1;
while ~feof(fp)
    line = fgetl(fp);
    if (line(1) ~= '%') && ischar(line)
        value(found) = sscanf(line,'%*s %*s %f');
        found = found + 1;
    end
end

The %*s skips the 'lat' or 'long' and the '='.

The example you provided is kinda well-behaved, therefore the following solution might need some tailoring. However, I would recommend it against any eval():

% Read whole file ignoring lines that start with '%' and using '=' as delimiter
fid = fopen('test.txt');
s   = textscan(fid,'%s%f', 'CommentStyle','%','Delimiter','=');
fclose(fid);

% Identify lines with latitude and those with longitude
idxLat = strncmpi('lat',s{1},3);
idxLon = strncmpi('lon',s{1},3);

% Store all latitudes and longitudes
lat = s{2}(idxLat);
lon = s{2}(idxLon);

Gets you a structure with field names matching parameter names, accepts comma-separated lists. List any parameters that should stay as strings in char_params

char_params={};
fid = fopen(filename);
% Load lines into cell (1x1) containing cell array s (Nx1), 
% skipping lines starting with % and cutting off anything after % in a line
s   = textscan(fid,'%s', 'CommentStyle','%','Delimiter','%');
fclose(fid);
% access the lines strings s{1}, split across '=' and remove whitespace on     both sides
s=strtrim(split(s{1},'='));
% Interpret parameters and save to structure
for ind=1:length(s)
%    User says which parameters are strings
    if any(strcmpi(s{ind,1},char_params))
        file_struct.(s{ind,1})=s{ind,2};
    % Otherwise, assume they are numbers or numeric row arrays
    else
%         remove parentheses and brackets
        trim_s=regexprep(s(ind,2),'[[]()]','');
%         convert comma-separated lists into row arrays
        file_struct.(s{ind,1})=str2double(split(trim_s{1},',')).';
    end
end
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!