如何在MATLAB中检索函数参数的名称?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (162)

除了解析函数文件,有没有办法将输入和输出参数的名称获取到matlab函数中?

例如,给定以下文件:

divide.m

function [value, remain] = divide(left, right)
     value = floor(left / right);
     remain = left / right - value;
end

从函数外部,我想获得一个输出参数数组,在这里:['value', 'remain'],对于输入参数也是如此:['left', 'right']

在MATLAB中有一种简单的方法吗?MATLAB通常似乎很好地支持反射。

编辑背景:

这样做的目的是在用户输入的窗口中显示功能参数。 我正在写一种信号处理程序,并且对这些信号执行操作的功能存储在子文件夹中。 我已经有了一个列表和用户可以选择的每个函数的名字,但是一些函数需要额外的参数(例如,一个平滑的函数可能会将窗口大小作为参数)。

目前,我可以为程序将找到的子文件夹添加一个新功能,用户可以选择它执行操作。 我缺少的是用户指定输入和输出参数,并且在这里我遇到了障碍,因为我找不到函数的名称。

提问于
用户回答回答于

如果你的问题局限于你想要解析文件中主函数的函数声明行的简单情况(即你不会处理子函数,嵌套函数或匿名函数),那么你可以提取输入并使用一些标准字符串操作和正则表达式输出参数名称,因为它们出现在文件中。 函数声明行具有标准格式,但您必须考虑以下几种变体:

  • 不同数量的空白或空行,
  • 存在单行注释或块注释,
  • 声明分成多行。

(事实证明,解释一个块评论是最棘手的部分...)

我已经安排了一个功能get_arg_names这将解决上述所有问题。如果您给它一个函数文件的路径,它将返回两个包含输入和输出参数字符串的单元格数组(如果没有,则返回空单元格数组)。请注意,带有变量输入或输出列表的函数将简单地列出。'varargin''varargout'分别用于变量名。以下是函数:

function [inputNames, outputNames] = get_arg_names(filePath)

    %# Open the file:
    fid = fopen(filePath);

    %# Skip leading comments and empty lines:
    defLine = '';
    while all(isspace(defLine))
        defLine = strip_comments(fgets(fid));
    end

    %# Collect all lines if the definition is on multiple lines:
    index = strfind(defLine, '...');
    while ~isempty(index)
        defLine = [defLine(1:index-1) strip_comments(fgets(fid))];
        index = strfind(defLine, '...');
    end

    %# Close the file:
    fclose(fid);

    %# Create the regular expression to match:
    matchStr = '\s*function\s+';
    if any(defLine == '=')
        matchStr = strcat(matchStr, '\[?(?<outArgs>[\w, ]*)\]?\s*=\s*');
    end
    matchStr = strcat(matchStr, '\w+\s*\(?(?<inArgs>[\w, ]*)\)?');

    %# Parse the definition line (case insensitive):
    argStruct = regexpi(defLine, matchStr, 'names');

    %# Format the input argument names:
    if isfield(argStruct, 'inArgs') && ~isempty(argStruct.inArgs)
        inputNames = strtrim(textscan(argStruct.inArgs, '%s', ...
                                      'Delimiter', ','));
    else
        inputNames = {};
    end

    %# Format the output argument names:
    if isfield(argStruct, 'outArgs') && ~isempty(argStruct.outArgs)
        outputNames = strtrim(textscan(argStruct.outArgs, '%s', ...
                                       'Delimiter', ','));
    else
        outputNames = {};
    end

%# Nested functions:

    function str = strip_comments(str)
        if strcmp(strtrim(str), '%{')
            strip_comment_block;
            str = strip_comments(fgets(fid));
        else
            str = strtok([' ' str], '%');
        end
    end

    function strip_comment_block
        str = strtrim(fgets(fid));
        while ~strcmp(str, '%}')
            if strcmp(str, '%{')
                strip_comment_block;
            end
            str = strtrim(fgets(fid));
        end
    end

end
用户回答回答于

MATLAB提供了一种获取类元数据信息的方法(使用meta),但是这仅适用于OOP类,而不是常规函数。

一个技巧是动态编写类定义,其中包含要处理的函数的源,并让MATLAB处理源代码的解析(正如您想象的那样,这可能很棘手:函数定义行跨越多行,实际定义之前的注释等等)。

因此,在你的情况下创建的临时文件如下所示:

classdef SomeTempClassName
    methods
        function [value, remain] = divide(left, right)
            %# ...
        end
    end
end

然后可以传递给meta.class.fromName分析元数据..。


下面是这个黑客的一个快速而肮脏的实现:

function [inputNames,outputNames] = getArgNames(functionFile)
    %# get some random file name
    fname = tempname;
    [~,fname] = fileparts(fname);

    %# read input function content as string
    str = fileread(which(functionFile));

    %# build a class containing that function source, and write it to file
    fid = fopen([fname '.m'], 'w');
    fprintf(fid, 'classdef %s; methods;\n %s\n end; end', fname, str);
    fclose(fid);

    %# terminating function definition with an end statement is not
    %# always required, but now becomes required with classdef
    missingEndErrMsg = 'An END might be missing, possibly matching CLASSDEF.';
    c = checkcode([fname '.m']);     %# run mlint code analyzer on file
    if ismember(missingEndErrMsg,{c.message})
        % append "end" keyword to class file
        str = fileread([fname '.m']);
        fid = fopen([fname '.m'], 'w');
        fprintf(fid, '%s \n end', str);
        fclose(fid);
    end

    %# refresh path to force MATLAB to detect new class
    rehash

    %# introspection (deal with cases of nested/sub-function)
    m = meta.class.fromName(fname);
    idx = find(ismember({m.MethodList.Name},functionFile));
    inputNames = m.MethodList(idx).InputNames;
    outputNames = m.MethodList(idx).OutputNames;

    %# delete temp file when done
    delete([fname '.m'])
end

并且简单地运行为:

>> [in,out] = getArgNames('divide')
in = 
    'left'
    'right'
out = 
    'value'
    'remain'

扫码关注云+社区