我有一组匿名函数,我想将它们转换为字符串。通常,我只使用func2str
,但是问题是我希望将变量和内部函数扩展为它们的“ true”值。我遇到的问题是MATLAB会按名称保留这些名称,但会识别这些值。例子
classdef Bclass
properties
equation
end
function obj = Bclass(inEquation, inValue)
obj.equation = @(t,y) inEquation(t,y) * inValue;
end
function out = getStr(obj)
out = func2str(obj.equation);
end
end
问题在于,如果我们实际上说过func2str
,那么在我实际上希望它输出诸如@(t,y) inEquation(t,y) * inValue
之类的内容时,@(t,y) t*y * 5
调用正在输出b = Bclass(@(t,y) t*y, 5)
。
是否可以从MATLAB中检索这些变量值?
答案 0 :(得分:5)
您可以执行此操作,但是如果您的问题比上面给出的示例更加复杂(即,更复杂的匿名函数,多个嵌套级别等),它可能会很快变得非常困难。您必须使用functions
函数来获取有关函数句柄的信息,并且其行为可能在发行版之间发生变化。此外,您还必须进行大量的字符串操作(如下面所述,使用诸如regexp
,regexprep
,strsplit
和strrep
之类的函数)。 / p>
我试图在这里包括我能提供的最通用的方法,并允许以下可能性:
inEquation
可以是非匿名函数句柄(即@times
)。inEquation
可以直接传递而无需实际调用。inEquation
可以在匿名函数中多次调用。inEquation
的输入自变量的名称与其在obj.equation
中的调用自变量的名称不同。obj.equation
可以包含索引操作。首先,我们将初始化一些变量以模仿您的示例:
f1 = @(m, n) m*n; % Note the different variable names, but it will still work
inEquation = f1;
inValue = 5;
f2 = @(t, y) inEquation(t, y)*inValue; % Function constructed using workspace variables
接下来,我们将获得f2
的功能信息:
s = functions(f2);
varNames = fieldnames(s.workspace{1});
varValues = struct2cell(s.workspace{1});
out = s.function;
workspace
字段保存用于构造f2
的变量名称和值,而function
字段是您通过在以下位置调用func2str
获得的字符串f2
。我们还需要计算一些内容,以便我们可以正确解析f2
中的左括号和右括号:
openIndex = (out == '(');
closeIndex = (out == ')');
parenIndex = cumsum(openIndex-[false closeIndex(1:end-1)]).*(openIndex | closeIndex);
现在,我们将遍历工作空间变量,将它们的值转换为字符串(如果可能),然后将其替换为out
:
for iVar = 1:numel(varNames)
name = varNames{iVar};
value = varValues{iVar};
if isa(value, 'function_handle') % Workspace variable is a function handle
value = func2str(value);
callIndex = strfind(out, [name, '('])+numel(name);
fcnParts = regexp(value, '@\({1}([^\)])*\){1}(\S)*', 'once', 'tokens');
if isempty(callIndex) % Function handle is not invoked
if isempty(fcnParts) % Non-anonymous function handle (i.e. @times)
value = ['@' value];
end
out = strrep(out, name, value);
elseif isempty(fcnParts) % Invoked function handle (i.e. @times)
out = strrep(out, name, value);
else % Invoked anonymous function handle
for iCall = callIndex
args = out(iCall+(1:find(parenIndex(iCall+1:end) == parenIndex(iCall), 1)-1));
value = regexprep(fcnParts{2}, ...
strcat('(?<!\w)', strsplit(fcnParts{1}, ','), '(?!\w)'), ...
strsplit(args, ','));
out = strrep(out, [name, '(', args, ')'], value);
end
end
elseif isnumeric(value) && isscalar(value) % Workspace variable is a numeric scalar
out = strrep(out, name, num2str(value));
end
end
我们得到out
的理想结果:
>> out
out =
@(t,y)t*y*5
请注意,这也将与非匿名函数句柄一起正常工作:
>> f1 = @times;
>> inEquation = f1;
>> inValue = 5;
>> f2 = @(t, y) inEquation(t, y)*inValue;
% Repeat above processing...
>> out
out =
@(t,y)times(t,y)*5
它还将在一些更复杂的功能上起作用:
>> postVolt = @(g, V) -.05*g*(V+80);
>> preIdx = 5;
>> postIdx = 1;
>> index = 6;
>> obj.values = {};
>> f2 = @(t) postVolt(obj.values{preIdx}(index), obj.values{preIdx}(obj.voltIdx{postIdx}));
% Repeat above processing...
>> out
out =
@(t)-.05*obj.values{5}(6)*(obj.values{5}(obj.voltIdx{1})+80)