delphifindfirst

FindFirst and question mark


I need to delete all files, which names are started with "a", then three arbitrary letters and ".txt" extension like "a123.txt". Here is the code:

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;

I always thought that the question mark means one and only one character, but to my surprise found that this code returns "a.txt", "a1.txt" and "a123.txt" file names. Is there a simple way to modify the code for it to seek only files like "a123.txt"?


Solution

  • The simplest solution for your specific need is to replace this:

    ShowMessage(tsrMessage.Name);
    

    with this

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

    this will ensure that the length of the file name is exactly four characters + the period + the extension. Like David says, there's no way to have the API do this kind of filtering, so you'll have to do it yourself, but in your particular case, there's no need to enumerate the entire directory. You may at least let the API do the filtering it can do, and then do your own filtering on top of it.

    EDIT: If you need to ensure that the three characters following the "a" are digits, you can do it this way:

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

    provided you are using a modern compiler (you'll need to include the "Characters" unit). Also take note that if you are compiling a mobile version, you'll need to use index [1], [2] and [3] instead, as they start index at 0 for strings.

    If you are using an older version, you can do it like this:

    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);