考虑以下代码
x = input('Input an array: ');
如果用户输入[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')
作为输入会发生什么?由于评估了输入,它实际上是a
命令将由Matlab执行。因此用户可以在路径中添加文件夹。更糟糕的是,如果他们输入path('')
,路径将被有效地更改为空,并且Matlab将停止正常工作。
另一个潜在的问题来源是
[...]要评估表达式,
input
访问当前工作区中的变量。
例如,如果用户输入fprintf(1,'%f', varname)
并且varname
是现有数字数组,则用户将知道其当前值。
这种行为可能是设计上的。输入数据时,Matlab程序的用户是可信的,就像他们被信任不要按 Control - C 来暂停程序(然后发出所有命令或检查所有变量)他们喜欢!)。
但在某些情况下,程序员可能希望获得更多"安全" input
函数,我的意思是
因此[1 2]
是有效输入,但由于第1项,[sqrt(2) sin(pi/3)]
或path''
不会;由于第2项,[1 2 3 varname(1)]
也无效。
答案 0 :(得分:6)
我找到了一个不太令人满意的解决方案(而且我喜欢阅读更好的解决方案)。它使用半文档功能,意味着将用户输入保存到临时文件。 Yair Altman's blog中提到的函数是getcallinfo
。根据{{1}}:
help getcallinfo
返回调用函数及其第一行和最后一行 此功能不受支持,可能会更改或删除 在将来的版本中注意。
此函数解决问题1(阻止函数调用)。对于问题2(防止访问变量),评估函数内的输入就足够了,因此它无法看到其他变量。显然(参见下面的示例2),getcallinfo
不仅会检测被调用的函数,还会检测变量。无论如何,在功能的孤立范围内进行评估可能是个好主意。
程序是:
使用getcallinfo
的字符串版本来阻止评估:
input
将字符串保存到文件中:
x = input('Input an array: ', 's');
使用filename = 'tmp.m';
fid = fopen(filename,'w');
fprintf(fid, '%s',x);
fclose(fid);
检查输入字符串以检测可能的函数调用:
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
是以下函数
evalinput
考虑
function x = evalinput(x)
x = eval(x);
用户输入
x = input('Input an array: ', 's');
然后
[sqrt(2) sin(pi/3)]
生成非空filename = 'tmp.m';
fid = fopen(filename,'w');
fprintf(fid, '%s',x);
fclose(fid);
gci = getcallinfo(filename);
,
gci.calls.fcnCalls.names
告诉我们,如果评估,用户输入将调用函数>> gci.calls.fcnCalls.names
ans =
'sqrt' 'sin' 'pi'
,sqrt
和sin
。请注意,pi
等运算符不会被检测为函数。
/
用户输入
y = [10 20 30];
x = input('Input an array: ', 's');
然后
[1 y y.^2]
产生
filename = 'tmp.m';
fid = fopen(filename,'w');
fprintf(fid, '%s',x);
fclose(fid);
gci = getcallinfo(filename);
因此>> gci.calls.fcnCalls.names
ans =
'y' 'y'
检测到变量就好像它们是函数一样。
答案 1 :(得分:1)
如果我正确理解你的问题,可以使用正则表达式来完成你想要做的事情。
无函数或变量调用
最简单的方法是检查输入字符串中是否没有字母字符。对于包含输入的x
,表达式将是
expr = '[a-zA-Z]';
x = input('Input an array: ', 's');
valid = isempty(regexp(x,expr));
仅此一点适用于上面给出的几个例子。
允许某些功能或变量
假设您想要允许用户访问某些变量或函数,可能是简单的trig函数,或者pi
或者您有什么,那么它就不再那么简单了。我一直在玩下面的表达式:
expr = '(?!cos\(|pi|sin\()[a-zA-Z]+
但它并没有完全符合预期。它将与in(
中的sin
匹配。如果你比我更了解正则表达式,你可以按摩它以正常工作。
否则,另一种方法是:
isempty(regexp(regexprep(x,'(sin\(|cos\(|pi|x)',''),expr))
以便删除您感兴趣的字符串。
希望这有帮助。
更新:为了允许虚数/ exp值和路径
要匹配的新表达式变为
expr = '[iIeE][a-zA-Z]+';
这会忽略i / I和e / E(你可以根据需要增加它)。你也可以通过切换到\{2,}
来实现两个字符的限制,尽管我的人仍然可以有一个字符匿名函数..
检查输入的另一部分是:
isempty(regexp(regexprep(x,'(sin\(|cos\(|pi|x|''(.*?)'')',''),expr))
现在您可以排除自定义函数(您可以将其作为数组,并通过|
将它们连接在一起)和路径。
以下是一些与通常一起测试的例子:
<强>通行证强>
'[1+2i, 34e12]'
'''this is a path'''
'[cos(5), sin(3+2i)]'
<强>失败强>
'[1+2ii, 34e12]'
'this is not a path'
'''this is a path'' this is not'