0

名前が「a」で始まり、任意の 3 文字と「a123.txt」のような「.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;

クエスチョン マークは 1 文字だけを意味するといつも思っていましたが、驚いたことに、このコードは "a.txt"、"a1.txt"、"a123.txt" というファイル名を返します。「a123.txt」のようなファイルのみを検索するようにコードを変更する簡単な方法はありますか?

4

2 に答える 2

4

この動作は設計どおりです。ここで Raymond Chen によって説明されています。

コマンド インタープリターからはまったく同じ動作が見られます。

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 バイト空き

( WindowsFindFirstFileの RTL の背後にある API)を説得して希望どおりに動作させる方法はありません。FindFirst最適なオプションは、ディレクトリ全体を列挙し、選択したパターン マッチング アルゴリズムを使用して独自のフィルタリングを実行することです。

于 2016-06-26T13:06:56.347 に答える
4

特定のニーズに対する最も簡単な解決策は、これを置き換えることです。

ShowMessage(tsrMessage.Name);

これとともに

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

これにより、ファイル名の長さが正確に 4 文字 + ピリオド + 拡張子になります。David が言うように、API でこの種のフィルタリングを行う方法はないため、自分で行う必要がありますが、特定のケースでは、ディレクトリ全体を列挙する必要はありません。少なくとも、API が実行できるフィルタリングを API に実行させ、その上で独自のフィルタリングを行うことができます。

編集:「a」に続く 3 文字が数字であることを確認する必要がある場合は、次の方法で行うことができます。

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

最新のコンパイラを使用している場合 ("Characters" ユニットを含める必要があります)。また、モバイル バージョンをコンパイルする場合は、代わりにインデックス [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);
于 2016-06-26T16:05:55.983 に答える