How do I use MATLAB's inputParser with optional string inputs? The documentation says "use a validation function" but it's unclear how to do that

Mic*_*l A 5 validation matlab function optional-arguments input-parameters

I have a MATLAB file that contains a single top-level function, called sandbox. That function in turn contains two nested functions, mysum and myprod, which are identical in functionality and what parameters they allow except that one uses @sum internally and the other uses @prod internally. My goal is to create a wrapper function to use in both mysum and myprod that takes care of all the validation and input parsing. This function is called applyFunc.

Here's where it gets tricky. mysum and myprod come in two forms:

  1. mysum(v) returns sum(v, 1).
  2. mysum(v, 'imag') returns sum(v, 1) + 1i

Any other combinations of input should throw an error.

I'm having trouble using inputParser to parse these various combinations of input, specifically the optional string input. Here's the code:

function sandbox()
%% Data
v = [1 4; 3 3];

%% Calculations
s = mysum(v);
si = mysum(v, 'imag');
p = myprod(v);
pi = myprod(v, 'imag');

%% Accuracy tests
assert(isequal(s, [4 7]))
assert(isequal(si, [4+1i 7+1i]))
assert(isequal(p, [3 12]))
assert(isequal(pi, [3+1i 12+1i]))

    function x = mysum(varargin)
        x = applyFunc(@sum, varargin{:});
    end

    function x = myprod(varargin)
        x = applyFunc(@prod, varargin{:});
    end
end

function x = applyFunc(func, varargin)

p = inputParser();
p.addRequired('func', @(x) validateattributes(x, {'function_handle'}, {'scalar'}));
p.addRequired('v', @(x) validateattributes(x, {'double'}, {}, 'applyFunc:msg', 'v'));
p.addOptional('imag', '', @(x) validatestring(x, {'imag', ''})); % THIS LINE IS THE PROBLEM
p.parse(func, varargin{:});

f = p.Results.func;
v = p.Results.v;
strflag = p.Results.imag;

x = f(v);
if ~isempty(strflag)
    validatestring(strflag, {'imag'});
    x = x + 1i;
end
end
Run Code Online (Sandbox Code Playgroud)

The line that's causing the problem is this one (as marked in the code above):

p.addOptional('imag', '', @(x) validatestring(x, {'imag', ''}));
Run Code Online (Sandbox Code Playgroud)

The documentation for inputParser says that:

For optional string inputs, specify a validation function. Without a validation function, the input parser interprets valid string inputs as invalid parameter names and throws an error.

Unfortunately I don't have any idea how to do this. Is there something simple Im missing or what? If the 'imag' argument isn't passed at all (as in the assignment of s and p), the code works fine, but if I do pass it, I get this error:

Error using sandbox>applyFunc (line 32)
The value of 'imag' is invalid. It must satisfy the function:
@(x)validatestring(x,{'imag',''}).
Error in sandbox/mysum (line 18)
        x = applyFunc(@sum, varargin{:});
Error in sandbox (line 7)
si = mysum(v, 'imag'); 
Run Code Online (Sandbox Code Playgroud)

Any help?

cha*_*pjc 5

The problem is that validatestring returns the matching string from the cell argument ({'imag',''}) rather than a Boolean indicating if it passes validation. Instead, use strcmp and any:

@(x) any(strcmp(x,{'imag', ''}))
Run Code Online (Sandbox Code Playgroud)

Also, with validatestring, if the input string did not match either 'imag' or '' (actually just 'imag' since empty strings only match in R2014a+), it would throw an error rather than returning false so that the inputParser could return the appropriate error.

解决该问题的另一个好方法是applyFunc完全更改语法,以便将Parameter-Value with作为参数并使用经过验证的布尔值作为输入,而不是'imag'作为可选的字符串输入参数。'imag'

Amro 在评论中建议的输入定义:

p.addParameter('imag', false, @(x)validateattributes(x, {'logical'}, {'scalar'}))
Run Code Online (Sandbox Code Playgroud)

用法:

mysum(x,'imag',true)
mysum(x)               % default is equivalent to mysum(x,'imag',false)
Run Code Online (Sandbox Code Playgroud)

这将p.Result.imag通过logical标量简化其余代码。我会建议:

x = f(v) + p.Result.imag*1i;
Run Code Online (Sandbox Code Playgroud)

  • +1 使用 `strcmp` 解决了这个问题。我个人不喜欢“可选参数”,我宁愿使用名称-值参数参数:`p.addParameter('imag', false, @(x)validateattributes(x, {'logical'}, {'标量'}))`。那么`p.Result.imag` 要么为真,要么为假。 (3认同)