Matlab 防止;输入“;函数调用函数或访问变量

Matlab 防止;输入“;函数调用函数或访问变量,matlab,input,user-input,Matlab,Input,User Input,考虑到以下代码 x = input('Input an array: '); 如果用户键入[1 2 3],变量x将被分配该数值向量。类似地,如果它们键入{1[23],'abc'},变量x将是包含这些值的单元格数组。好的 现在,如果用户键入[sqrt(2)sin(pi/3)],变量x将被分配结果值:[1.414213562373095 0.866025403784439]。这是因为所提供的数据是通过以下方式评估的: 输入提示用户输入 result=input(prompt)在屏幕上显示promp

考虑到以下代码

x = input('Input an array: ');
如果用户键入
[1 2 3]
,变量
x
将被分配该数值向量。类似地,如果它们键入
{1[23],'abc'}
,变量
x
将是包含这些值的单元格数组。好的

现在,如果用户键入
[sqrt(2)sin(pi/3)]
,变量
x
将被分配结果值:
[1.414213562373095 0.866025403784439]
。这是因为所提供的数据是通过以下方式评估的:

输入
提示用户输入
result=input(prompt)
在屏幕上显示
prompt
字符串,等待 对于键盘输入,计算输入中的任何表达式, 并返回
结果中的值。[……]

这可能会导致问题。例如,如果用户键入
addpath('c:\path\to\folder')
作为输入,会发生什么?因为输入是经过计算的,所以它实际上是一个 该命令将由Matlab执行。因此,用户可以在路径中添加文件夹。更糟糕的是,如果他们输入
路径(“”)
,路径将有效地变为零,Matlab将停止正常工作

另一个潜在的问题来源是

[…]要计算表达式,
input
访问当前工作区中的变量

例如,如果用户输入的
fprintf(1,'%f',varname)
varname
是现有的数值数组,则用户将知道其当前值

这种行为可能是故意的。Matlab程序的用户在输入数据时是受信任的,就像他们被信任不按Control-C停止程序一样(然后发出所有命令或检查所有他们喜欢的变量!)

但在某些情况下,程序员可能希望有一个更“安全”的
输入功能,我的意思是

  • 在评估用户时防止任何函数调用 输入;及
  • 防止输入访问程序变量

  • 因此
    [12]
    将是有效的输入,但是
    [sqrt(2)sin(pi/3)]
    路径(“”)
    将不会因为第1项而生效;而
    [1 2 3 varname(1)]
    也将因第2项而无效。

    我发现了一个不太令人满意的解决方案(我想了解一个更好的解决方案)。它使用一个半文档化的功能,并意味着将用户输入保存到一个临时文件。中提到的函数是
    getcallinfo
    。根据
    帮助获取CallInfo

    getcallinfo

    返回被调用函数及其第一行和最后一行
    此函数不受支持,可能会更改或删除,而无需 请在将来的版本中注意

    此函数解决问题1(防止函数调用)。至于问题2(阻止访问变量),在函数中计算输入就足够了,这样就看不到其他变量了。显然(参见下面的示例2),
    getcallinfo
    不仅检测调用的函数,还检测变量。无论如何,在函数的隔离范围内进行计算可能是个好主意

    程序如下:

  • 使用
    输入的字符串版本来防止计算:

    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);
    
    例1 考虑

    x = input('Input an array: ', 's');
    
    用户输入

    [sqrt(2) sin(pi/3)]
    
    然后

    生成非空的
    gci.calls.fcnCalls.names

    >> gci.calls.fcnCalls.names
    ans = 
        'sqrt'    'sin'    'pi'
    
    这告诉我们,如果进行计算,用户输入将调用函数
    sqrt
    sin
    pi
    。请注意,诸如
    /
    之类的运算符不会被检测为函数

    例2 用户输入

    [1 y y.^2]
    
    然后

    产生

    >> gci.calls.fcnCalls.names
    ans = 
        'y'    'y'
    

    因此,变量被
    getcallinfo
    检测,就好像它们是函数一样。

    如果我正确理解了您的问题,就可以使用正则表达式来完成您要做的事情

    没有函数或变量调用

    最简单的方法是检查输入字符串中是否没有字母字符。对于包含输入的
    x
    ,表达式将是:

    expr = '[a-zA-Z]';
    x = input('Input an array: ', 's');
    valid = isempty(regexp(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'
    
    假设您希望允许用户访问一些变量或函数,可能是简单的trig函数,或
    pi
    或您拥有的其他函数,那么它就不再那么简单了。我一直在玩弄下面这样的表达:

    expr='(?!cos\(| pi | sin\()[a-zA-Z]+

    但是它并没有达到预期的效果。它将在(
    in
    sin
    中匹配
    。如果你比我更了解regex,你可以通过按摩使其正常工作

    否则,另一种方法是:

    isempty(regexp(regexprep(x,'(sin\(|cos\(|pi|x)',''),expr))
    
    这样您就可以删除感兴趣的字符串

    希望这有帮助

    更新:为了允许虚拟/exp值和路径

    '[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'
    
    要匹配的新表达式变为

    expr = '[iIeE][a-zA-Z]+';
    
    这忽略了i/i和e/e(您可以根据自己的需要进行扩展)。您也可以通过切换到
    \{2,}
    ,来限制两个字符,尽管i-people仍然可以使用一个字符的匿名函数

    检查输入的另一部分变成:

    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'
    
    失败

    '[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'
    

    感谢分享!如果只是关于读取一组数字,您可以再次