Lui*_*ndo 8 matlab user-input input
考虑以下代码
x = input('Input an array: ');
Run Code Online (Sandbox Code Playgroud)
如果用户键入[1 2 3],变量x将被赋予该数字向量.同样,如果键入{1, [2 3], 'abc'},变量x将是包含这些值的单元格数组.精细.
现在,如果用户键入[sqrt(2) sin(pi/3)],x将为变量分配结果值:[1.414213562373095 0.866025403784439].那是因为提供的数据通过以下方式评估input:
input提示用户输入.在屏幕上
result = input(prompt)显示prompt字符串,等待键盘输入,评估输入中的任何表达式,并返回值result.[...]
这可能会导致问题.例如,如果用户addpath('c:\path\to\folder')输入输入会发生什么?由于评估了输入,它实际上是一个由Matlab执行的命令.因此用户可以在路径中添加文件夹.更糟糕的是,如果他们输入path(''),路径将被有效地改为零,Matlab将停止正常工作.
另一个潜在的问题来源是
[...]要计算表达式,请
input访问当前工作空间中的变量.
例如,如果用户输入fprintf(1,'%f', varname)并且varname是现有数字数组,则用户将知道其当前值.
这种行为可能是设计的.Matlab程序的用户在输入数据时是可信的,就像他们被信任不要按Control- C停止程序(然后发出所有命令或检查他们喜欢的所有变量!).
但在某些情况下,程序员可能希望拥有一个更"安全"的input功能,我的意思是
那么[1 2]是有效的输入,但是[sqrt(2) sin(pi/3)]或者path''因为第1项而不是; 并且[1 2 3 varname(1)]将无效也因为2项.
我找到了一个不太令人满意的解决方案(我很想读一个更好的解决方案).它使用半文档化的功能,意味着将用户输入保存到临时文件中.Yair Altman的博客中提到的这个功能是getcallinfo.根据help getcallinfo:
getcallinfo返回称为函数及其第一行和最后一行
此函数不受支持,可能会在将来的版本中更改或删除,恕不另行通知.
此函数解决了问题1(阻止函数调用).对于问题2(阻止访问变量),评估函数内的输入就足够了,因此它无法看到其他变量.显然(参见下面的示例2),getcallinfo不仅检测被调用的函数,还检测变量.无论如何,在功能的隔离范围内进行评估可能是个好主意.
那么程序是:
使用字符串版本input来阻止评估:
x = input('Input an array: ', 's');
Run Code Online (Sandbox Code Playgroud)将字符串保存到文件:
filename = 'tmp.m';
fid = fopen(filename,'w');
fprintf(fid, '%s',x);
fclose(fid);
Run Code Online (Sandbox Code Playgroud)检查输入字符串getcallinfo以检测可能的函数调用:
gci = getcallinfo(filename);
if ~isempty(gci.calls.fcnCalls.names)
%// Input includes function calls: ignore / ask again / ...
else
x = evalinput(x); %// evaluate input in a function
end
Run Code Online (Sandbox Code Playgroud)evalinput以下功能在哪里?
function x = evalinput(x)
x = eval(x);
Run Code Online (Sandbox Code Playgroud)
考虑
x = input('Input an array: ', 's');
Run Code Online (Sandbox Code Playgroud)
用户输入
[sqrt(2) sin(pi/3)]
Run Code Online (Sandbox Code Playgroud)
然后
filename = 'tmp.m';
fid = fopen(filename,'w');
fprintf(fid, '%s',x);
fclose(fid);
gci = getcallinfo(filename);
Run Code Online (Sandbox Code Playgroud)
产生一个非空的gci.calls.fcnCalls.names,
>> gci.calls.fcnCalls.names
ans =
'sqrt' 'sin' 'pi'
Run Code Online (Sandbox Code Playgroud)
这告诉我们,用户的输入会调用函数sqrt,sin并且pi如果评估.请注意,诸如之类的运算符/未被检测为函数.
y = [10 20 30];
x = input('Input an array: ', 's');
Run Code Online (Sandbox Code Playgroud)
用户输入
[1 y y.^2]
Run Code Online (Sandbox Code Playgroud)
然后
filename = 'tmp.m';
fid = fopen(filename,'w');
fprintf(fid, '%s',x);
fclose(fid);
gci = getcallinfo(filename);
Run Code Online (Sandbox Code Playgroud)
产生
>> gci.calls.fcnCalls.names
ans =
'y' 'y'
Run Code Online (Sandbox Code Playgroud)
因此,变量getcallinfo就像它们是函数一样被检测到.