Pergunta

In a matlab program I have an external parameter file that needs to be read in. Like

a = 1/3
b = 'test'

Currently I use textscan to read this file and use str2num to parse the values of a. However, I read that str2num use eval inside, which is undesirable for safety reason: what if someone made a = 'delete something', and then str2num will execute the string as a side effect. str2double does not work for fractional numbers. Is there any better way to parse 1/3 from external file into matlab?

Foi útil?

Solução

If you are going to parse input that can only be a simple number or a division, the str2double/str2double approach may be sufficient. However if you want to parse input safely in general, I would recommend restricting the input.

For example like so:

rawString= 'dir+3/5'
safeCharacters = ['0':'9' '+-*/\^eEij. '];

if all(ismember(rawString,safeCharacters))
   str2num(junkString)
end

Of course this may filter out some potentially good input like: str2num('rand')

Outras dicas

Personally, I'd use str2num (which is based on eval if you read the documentation). However, another option is sym. The Symbolic Math toolbox is based on eval as well of course, but it has input validation to avoid the potential dangers you're worried about. It is very robust and simple to use for what you need:

a = '1/3';
a = double(sym(a))

This also handles converting cell arrays of strings to vectors and matrices gracefully:

a={'1/3','1/33','1/333'; ...
   '2/3','2/33','2/333'};
a = double(sym(a))

The following unlikely input will return warnings and an error (and not delete a in memory):

b = 'delete a';
a = double(sym(b))

Thus you may want to use a try/catch statement to gracefully handle cases when a user may provide invalid input:

try
    Xs = double(sym(X));
catch err
    if strcmp(err.id,'MATLAB:UndefinedFunction')
        error('YourFunctionName:UnknownInput','Your helpful message here.');
    else
        rethrow(err);
    end
end

You could equally replace the Xs = double(sym(X)); line with a call to str2num.

You can explicitly search for the backslash with strfind.

if ~isempty(strfind(X, '/'))
   % then use str2num
else
   % use str2double, and if this returns a NaN, then it is a string
end

Or use strtok to split the string using '/' as a token, and use str2double on all resulting elements.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top