I need to validate a function of 'x' on matlab using a string field from a guide object. It must only have numbers, operations and 'x'. I tried many hours and I could not build a piece of code to complete this task. Does anyone can help me, or at least tell me how this can be done?
-
What operations are you accepting? Are you allowing for parentheses? – GrapefruitIsAwesome May 27 '23 at 10:37
1 Answers
Maybe you could let the MATLAB parser do most of the work for you. You could check that the only variable present is x and use eval( ) to check syntax. E.g., something like this:
% flag = validatex(s) checks s for valid expression involving only x
%
% Uses MATLAB parser for syntax checking, may fail if x is not assumed scalar
%
% s = char or string expression
% flag = 0 , s contains a variable other than x or is invalid expression
% 1 , s is a valid expression that contains only x variable
%
function flag = validatex(s)
flag = 0; % default return is invalid
if( ischar(s) || isstring(s) ) % make sure input is char or string type
v = symvar(s); % use sym engine to find all variables
if( any(cellfun(@(c)~isequal(c,'x'),v)) ) % check for variables other than x
return;
end
try
x = 1; % Put an arbitrary variable x in workspace for eval( ) to use
e = eval(s); % check syntax
flag = 1; % passed syntax check and has only x variable
catch
end
end
end
If you require x to be present in the expression, then add another check immediately before the try:
if( ~any(cellfun(@(c)isequal(c,'x'),v)) ) % make sure x is present
return;
end
Or could make only one cellfun( ) call and then use the results of that downstream. E.g.,
xcheck = cellfun(@(c)isequal(c,'x'),v);
% then use xcheck to check for x and non-x variables downstream
EDIT ---------------------------------------------------------
Based on Cris's very important point, I offer this version that uses a simple token search instead, disallowing anything that isn't x or doesn't start with a numeric digit. Or could easily be modified to allow only function names from an approved list (example shown in code). Caveat: Some quick checks shows that the token parsing can get fooled by string literals, interpreting the contents of the string as separate tokens. Given that the ' character can be used for both complex conjugate transpose and char literals, I don't see an easy workaround at the moment. So you might get failures for benign string literals in the input.
Note that in both code versions, if the expression doesn't work for a scalar x then it will fail validation. So if you need matrix or array expression indexing in the expression, then the code would have to be modified. The tokens( ) code was copied from a MATLAB Answers post. But, per my comment below, neither of these validation checks prevents the user's downstream code from calling a function named x and potentially executing malicious code.
% flag = validatex(s) checks s for valid expression involving only x
%
% Uses MATLAB parser for syntax checking, may fail if x is not assumed scalar
%
% s = char or string expression
% flag = 0 , s contains a variable other than x or is invalid expression
% 1 , s is a valid expression that contains only x variable
%
function flag = validatex(s)
flag = 0; % default return is invalid
if( ischar(s) || isstring(s) ) % make sure input is char or string type
approved = {'sin','cos','exp','ln'}; % an approved function name list
tok = tokens(s,'+-*/\^&|.,;><()[]{}');
hasx = 0;
for k=1:numel(tok)
if( isempty(tok{k}) )
% empty token is ok
elseif( isequal(tok{k},'x') || isequal(tok{k},'x''') )
hasx = 1;
elseif( tok{k}(1) >='0' && tok{k}(1) <='9' )
% numeric is ok
elseif( tok{k}(1) == '''' || tok{k}(1) == '"' )
% char or string literal is ok
elseif( ismember(tok{k},approved) )
% approved function name is ok
else
return; % anything else is disallowed
end
end
if( ~hasx ) % include this if x is required to be present
return
end
try
x = 1; % Put an arbitrary variable x in workspace for eval( ) to use
e = eval(s); % check syntax
flag = 1; % passed syntax check and has only x variable
catch
end
end
end
function tok = tokens(s,d)
% Simple string parser returns tokens in input string s
% returns tok as cell array of char strings
%
% T=TOKENS(S) returns the tokens in the string S delimited
% by "white space". Any leading white space characters are ignored.
%
% TOKENS(S,D) returns tokens delimited by one of the
% characters in D. Any leading delimiter characters are ignored.
% Get initial token and set up for rest
if( isstring(s) )
s = char(s);
end
if nargin==1
[tok,r] = strtok(s);
while ~isempty(r)
[t,r] = strtok(r);
tok = strvcat(tok,t);
end
else
[tok,r] = strtok(s,d);
while ~isempty(r)
[t,r] = strtok(r,d);
tok = strvcat(tok,t);
end
end
n = size(tok,1);
ctok = cell(n,1);
for k=1:n
ctok{k} = strtrim(tok(k,:));
end
tok = ctok;
end

- 2,242
- 8
- 9
-
This answer needs a big bold warning about the danger of evaluating anything the user inputs. I don’t think the validation here prevents calling arbitrary functions. – Cris Luengo May 27 '23 at 16:47
-
@Cris: That's a very good point. But presumably this expression is going to be called by the user downstream in their code anyway. I.e., this validation function isn't the only place this expression is going to be evaluated. To prevent malicious functions from being executed, I suppose one would have to examine the string and disallow all function calls. But, quite frankly, what's to prevent the user from having malicious code behind a function called x? I.e., even if there are no function calls and only the variable x present? – James Tursa May 27 '23 at 17:45