【问题标题】:FindFirst and question markFindFirst 和问号
【发布时间】:2016-06-26 12:53:44
【问题描述】:

我需要删除所有以“a”开头的文件,然后是三个任意字母和“.txt”扩展名,如“a123.txt”。代码如下:

var
  sFileMask: string;
  tsrMessage: TSearchRec;
begin
  sFileMask := 'c:/a???.txt';
  if SysUtils.FindFirst(sFileMask, 0, tsrMessage) = 0 then
  begin
    repeat
      ShowMessage(tsrMessage.Name);
    until FindNext(tsrMessage) <> 0;
    SysUtils.FindClose(tsrMessage);
  end;
end;

我一直以为问号的意思是一个且只有一个字符,但没想到这段代码返回的是“a.txt”、“a1.txt”和“a123.txt”文件名。有没有一种简单的方法可以修改代码以仅查找“a123.txt”之类的文件?

【问题讨论】:

    标签: delphi findfirst


    【解决方案1】:

    满足您特定需求的最简单解决方案是替换它:

    ShowMessage(tsrMessage.Name);
    

    有了这个

    if length(tsrMessage.Name)=8 then ShowMessage(tsrMessage.Name);
    

    这将确保文件名的长度正好是四个字符 + 句点 + 扩展名。就像大卫说的那样,没有办法让 API 进行这种过滤,所以你必须自己做,但在你的特定情况下,没有必要枚举整个目录。你至少可以让 API 做它可以做的过滤,然后在它上面做你自己的过滤。

    编辑:如果您需要确保“a”后面的三个字符是数字,您可以这样做:

    if (length(tsrMessage.Name)=8) and tsrMessage[2].IsDigit and tsrMessage[3].IsDigit and tsrMessage[4].IsDigit then ShowMessage(tsrMessage.Name);
    

    如果您使用的是现代编译器(您需要包含“字符”单元)。另请注意,如果您正在编译移动版本,则需要使用索引 [1]、[2] 和 [3],因为它们从 0 开始索引字符串。

    如果你使用的是旧版本,你可以这样做:

    function IsDigit(c : char) : boolean;
      begin
        Result:=(c>='0') and (c<='9')
      end;
    
    if (length(tsrMessage.Name)=8) and IsDigit(tsrMessage[2]) and IsDigit(tsrMessage[3]) and IsDigit(tsrMessage[4]) then ShowMessage(tsrMessage.Name);
    

    【讨论】:

    • 是的,我也想使用这种方法,但我使用的示例被简化了。实际上,我需要根据掩码删除文件,如 Format like a%03d.txt 等。在这种情况下,对于这样一个简单的任务,代码变得太复杂了,所以我决定我做错了什么。
    【解决方案2】:

    此行为符合设计。 Raymond Chen在这里解释:How did wildcards work in MS-DOS?

    您将在命令解释器中看到完全相同的行为。

    C:\Desktop>dir a???.txt 驱动器 C 中的卷没有标签。 卷序列号为 20DA-7FEB C:\Desktop 目录 26/06/2016 14:03 6 a.txt 26/06/2016 14:03 6 a1.txt 26/06/2016 14:03 6 a12.txt 26/06/2016 14:03 6 a123.txt 4 个文件 24 字节 0 Dir(s) 286,381,445,120 字节空闲

    无法说服 FindFirstFile(Windows 上 RTL 的 FindFirst 背后的 API)按照您的意愿行事。您最好的选择是枚举整个目录,并使用您选择的模式匹配算法执行您自己的过滤。

    【讨论】:

    • 谢谢,知道了,自从我上次使用这个通配符已经很久了,所以我 100% 确定“?”仅表示一个字符。
    • @Molochnik SQL 中的单字符通配符正如您所描述的那样工作 - 也许这就是您的困惑所在。它在现在之前抓住了我。问候,
    • @Michael 是的,这是可能的,但不太可能,十年来我一直在使用正则表达式表示法(之前我使用过 fnmatch),但我并没有想到仍然存在正则表达式没有通配符,表示单个字符。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-07-06
    • 1970-01-01
    • 2017-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多