2017-08-14 67 views
2

我试图构建自己的MATLAB版本dir函数。我目前的代码(下面)几乎可以工作,但我无法解析某些输入组合。函数'varargin'只给出名称 - 值对时给出错误:MATLAB

我想它做的是这样的:

  • 不要列出隐藏的文件夹。
  • 有一个布尔参数(默认为false)仅返回目录名称而不返回文件。
  • 有一个可选字段作为文件夹的路径(默认为当前目录)。

更清晰,我想创建功能dir2它能够处理这些组合:

  1. dir2这应该列出当前目录每一个不隐藏文件或文件夹
  2. dir2('path_to_directory')这应该列出指定目录中的每个非隐藏文件或文件夹
  3. dir2('OnlyDirectories', true)这应该只列出未隐藏的文件夹在当前目录
  4. dir2('path_to_directory', 'OnlyDirectories', true)这应该只列出在指定目录

我现在的版本是不是隐藏的文件夹这个:

function list = dir2(varargin) 
    p = inputParser; 

    addOptional(p, 'name', '.', @ischar); 
    addParameter(p, 'OnlyDirectories', false, @islogical); 
    parse(p, varargin{:}); 

    list = dir(p.Results.name); 
    if p.Results.OnlyDirectories 
     dirFlags = [list.isdir]; 
     list = list(dirFlags); % Keeping only directories 
    end 
    % Deleting hidden folders from the list 
    list = list(arrayfun(@(x) ~strcmp(x.name(1),'.'), list)); 
end 

这工作正常的情况下s , and 但它不适用于案件。在这种情况下,它给我的错误:

Expected a string scalar or character vector for the parameter name, instead the input type was 'logical'.

我想我可能会丢失关于MATLAB输入一些小事解析,但我想不出什么。

回答

2

你说得对,解析器似乎给出了一些奇怪的结果,相关的问题可能是this one

一个解决方法,它适用于您的函数在其当前形式,将添加检查是否给出2个输入。如果有2个输入,则假定它是您的OnlyDirectories标志并使用默认的name值。代码看起来像这样并且传递了所有4个示例用例。

function list = dir2(varargin) 
    p = inputParser; 
    addOptional(p, 'name', '.', @ischar); 
    addParameter(p, 'OnlyDirectories', false, @islogical); 
    if numel(varargin) == 2 
     varargin = [{'.'}, varargin]; 
    end 
    parse(p, varargin{:}); 
    list = dir(p.Results.name); 
    if p.Results.OnlyDirectories 
     dirFlags = [list.isdir]; 
     list = list(dirFlags); 
    end 
    list = list(arrayfun(@(x) ~strcmp(x.name(1),'.'), list)); 
end 

有点哈克虽然,有范围,给混乱的错误消息。这将是更好的只是有两个输入端为名称 - 值对

function list = dir2(varargin) 
    p = inputParser; 
    addParameter(p, 'name', '.', @ischar); 
    addParameter(p, 'OnlyDirectories', false, @islogical); 
    % ... other code 
end 

用途:dir2('name', 'C:/Folder/MyStuff/', 'OnlyDirectories', true)

+0

,而不是假设的东西,我想你可以检查它并相应采取行动。例如:1.检查你是否有2个参数(就像你现在做的那样)2.检查参数是否真的是你期望的3.要么处理它,要么明确地抛出相关的错误。 –

+0

是的,或者遍历所有'varargin'成员并根据其他标准分配变量。虽然正如我注意到的那样,无论如何,解决方案有点怪异,进一步的检查类似于将更多的磁带放在泄漏的管道上,而不是使用更好的管道! – Wolfie

0

你的问题是,你的validation functionoptional argument不够具体。如你所知,它只是检查它是否为character array。当您仅通过'OnlyDirectories', true作为第三种情况的参数时,字符串'OnlyDirectories'将通过您的验证功能并用作参数'name'的值。然后你会得到一个错误,因为剩下的参数是一个逻辑值而不是参数名称字符串。

以此为更严格的验证功能为我的作品:

addOptional(p, 'name', '.', @(d) (exist(d, 'dir') == 7)); 

这使用exist检查可选的参数是一个有效的文件夹。对于第三种情况,字符串'OnlyDirectories'未通过可选参数'name'的验证功能,因此将使用默认值并传递字符串以检查下一个参数。

编辑:

为了澄清,固有的问题是,你想包括一个可选的参数是一个字符串和参数值对总是要开始参数名字也是一个字符串。在这种情况下存在一些(可能不可避免的)模糊性,并且唯一的方法是通过您提供的验证功能,可以将可选字符串与后续参数值对的参数名称区分开来。如果它们之间的差异不能做得足够清楚,则应改为使用required argumentsparameter-value pairs。请注意,如果您的可选参数不是character array or string以外的任何参数,则这不会成为问题。但是,如果您使用的是可选参数,那么上面提供的用于更具体验证函数的示例只是一种方法。还有其他的选择可能更符合你的喜好。您可以改为检查可选参数字符串不是任何您函数的参数名:

addOptional(p, 'name', '.', @(d) ~ismember(d, {'OnlyDirectories', ...})); 

这都与你永远无法通过文件夹你的输入参数之一的名称来搜索的限制(无论您选择哪种解决方案,您都可能不得不接受这种歧义)。

还有另一种解决方案将允许您使用可选的参数一样'path_to_folder/*.csv'(即通配符指标和路径文件):

addOptional(p, 'name', '.', @name_check); 
... 

function isValid = name_check(d) 
    try 
    [dirPath, fileName, fileExt] = fileparts(d); 
    isValid = ismember('*', d) ... % A wildcard, not allowed in parameter names 
       || (isempty(fileExt) && (exist(d, 'dir') == 7)) ...  % A folder path 
       || (~isempty(fileExt) && (exist(dirPath, 'dir') == 7)); % A file path 
    catch 
    isValid = false; % Any failure of the above indicates an invalid argument 
    end 
end 
+0

我真的很喜欢这个答案,但是有一个问题。我知道这个问题没有明确说明,但是这种方法不允许我像这样调用函数:'dir2('path_to_folder/*。csv')'为了列出所有'.csv'文件在给定的路径。 如果给定的输入也是'dir'的有效输入,你是否认为有可能返回'true'的验证函数?或类似的东西 – jackscorrow

+0

在我看来,这是没有办法区分名称 - 值对和参数中的字符串。这是模棱两可的,反直觉和马车。例如,举个例子,如果你有一个名为“OnlyDirectories”的目录,会发生什么?正确的解决方案是@Wolfie的解决方案。 – crazyGamer

+0

你说得对。我没有想到这个选项 – jackscorrow