Arguments accept char, string or "cellstr" (cell array of char or string)

32 次查看(过去 30 天)
I have a large number of functions I eventually intend to be redistributable at my company. I had started creating my own variable validation routines but, fortunately I found the built in arguments block before I got too far down that road. It's very useful in data validation.
It's nice that arguments will allow not just strictly the given type/class of variable but will also allow anything that is convertible to that type (e.g. you can pass a string to char or char to string and any numeric types are also automatically converted). If you have two different types, it's a little trickier, but I've figured out how to use mustBeA and an array of strings of the types I want to accept.
One thing haven't figured out how to do effectively using this method. I have multiple aguments in multiple functions that can accept an input that is a char array, a string, or a cell array of char or string. I can use mustBeA to accept char, string, or cell - but I don't want to accept just any cell variable, it needs to be a cell array of char or string only, and it's not directly convertible. I know some MATLAB functions have sort of defined a type called cellstr which is a cell array of char or string - but that doesn't appear to be a checkable type in the arguments block.
I can, of course, add a block in my actual code to see if the argument matches iscell and then loop through the array and check all the elements but it would be nice if there's a way to do it within the arguments block.
Is there a way to do this inside the arguments block?

回答(3 个)

dpb 2023-2-8
You write a custom validation function that your code in the arguments block calls for special cases if you're using the supplied arguments checking routines.
I've not really adopted it as don't write "production" MATLAB code for others to use, but my "trick" for the specific case you've outlined above looks like
function res=myfunction(arg)
cellstr(arg); % throws error if any cell content isn't char or string
... % do whatever need here -- throw error, fixup if can, whatever...
The less tricky, more straightforward way would be to use something like
in the custom arg test function.
  4 个评论
Matt Cooper
Matt Cooper 2023-3-7
编辑:Matt Cooper 2023-3-7
The cellfun method should also check for cell arrays of cells containing text:
tf = all(cellfun(@(x)ischar(x)|isstring(x)|iscellstr(x),x),'all');


Les Beckham
Les Beckham 2023-2-8
Interesting issue. Looks like you have to create a "custom validation function". See if something like this works for you.
a = ones(1, 3);
Error using solution>Test
Invalid argument at position 1. inputArg1 must be string or char or cellstr
Test({'a', 'b'})
Test({"a", "b"})
function Test(inputArg1)
inputArg1 {mustBeStringCharOrCellstr(inputArg1)}
function mustBeStringCharOrCellstr(arg)
if ~isstring(arg) && ~ischar(arg) && ~iscellstr(arg)
eid = 'Test:notValid';
msg = 'inputArg1 must be string or char or cellstr';
throwAsCaller(MException(eid, msg))
  3 个评论
Les Beckham
Les Beckham 2023-2-8
编辑:Les Beckham 2023-2-8
Good to know. I actually haven't used the argument validation feature very much, so it is nice to learn new things about it so that, if and when I do use it, I will be more prepared.
Creating a cell array of strings, to me, sounds like just poor design, since you can already have arrays of arbitrary length strings. Note that the Matlab editor will even flag the creation of a cell array of strings with a Code Analyzer warning, and offer to fix it by converting it to an array of strings (square brackets instead of curly ones.)
So, maybe you should answer your own question with the mustBeText solution and accept that answer so people looking at this in the future will know about that solution. Note that you can also vote for answers that helped you (such as dpb's and mine) even if they aren't the "right" or accepted answer.


Captain Karnage
Captain Karnage 2023-2-8
编辑:Captain Karnage 2023-2-8
If cell arrays of strings wasn't a requirement, MATLAB already has an easy built-in solution with mustBeText:
thisarg { mustBeText(thisarg) };
To support cell arrays of strings - I've bobbled back and forth on what method I wanted to use. In the end I created a custom validation function derived from the source code of MATLABs mustBeText function. I added acceptance of a cell array of strings andI took it one step further and made it validate with any number of layers of cells. It has a safe recursion (by "safe" I mean it takes a layer off each time and so eventually must reach an end and cannot create an infinite loop). I struggled with naming this dang thing in a non-overbearing way that also says what it does, but here is my end result:
function mustContainOnlyText(arg)
%mustContainOnlyText validates that input contains only text
% argument is char, string, or a cell array of strings
% Intended for use within arguments block to validate an input
if ~containsOnlyText(arg)
eid = 'custom:validators:mustContainOnlyText';
msg = 'Value must be char, character vector, string array or scalar, or cell array of character vectors or strings.';
throwAsCaller(MException(eid, msg));
which calls the function:
function tf = containsOnlyText(text)
%containsOnlyText - checks that passed text contains only text
% In this context:
% "text" refers to char or string types
% "contains" means it could be text by itself,
% or either type contained within an array or cell
% Returns true if it contains only text
%Single Boolean Statement
%Removes outer cell layer and recurses if the passed text is in a cell array
%Text passed to next version is horizontally concatenated version
tf = ischar(text) || ...
isstring(text) || ...
iscell(text) && ( containsOnlyText( [text{:}] ) ); %If there are layered cells
and I can then add to the arguments block:
thisarg { mustContainOnlyText(thisarg) };
I'll probably tweak this some - I know that if someone passes a heterogenous array of cells it will cause an exception in the containsOnlyText function and not send the validation exception message (but, ultimately, it will still check for the correct type).
I'm contemplating adding try / catch in per @dpb. I'm normally opposed to a Try/Catch in "production" code because it could mask an exception - and I believe you should work to make the exception not possible instead of allowing the exception then patching around it. In this case though, try / catch would only serve to change the exception to a different exception.
Thank you to both @dpb and @Les Beckham who helped get me to this answer. And also yes, simple arrays of strings are much better than cell arrays of strings.
  3 个评论



Find more on Data Type Conversion in Help Center and File Exchange




Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by