1

ソートされ、一意のファイル名を含む TStringList があります。リストは任意のサイズにすることができます (したがって、数十万のエントリになる可能性があります)。エントリのいずれかが特定の文字列で始まるかどうかを確認したい (つまり、ファイルがサブフォルダにあるかどうか)。リストを連続的にスキャンして StartsText を使用するのは簡単ですが、それは理想的な解決策ではありません。

TStringList.Find() コードを出発点として使用して、解決策と思われる関数を作成しましたが、確認したいと思います。以下がクラスのメンバーでなくても心配する必要はありません (FList は検索対象の TStringList インスタンスです)。StartsFilename は StartsText と同じように機能します。

  function ShortcutFind(const S: string): Boolean;
  var
    L, H, I, C: Integer;
  begin
    Result := False;
    L := 0;
    H := FList.Count - 1;
    while L <= H do begin
      I := (L + H) shr 1;

      if TFilenameUtils.StartsFilename(FList[I], aFolder) then begin
        Result:=TRUE;
        Exit;
      end;

      C := FList.CompareStrings(FList[I], S);
      if C < 0 then
        L := I + 1
      else begin
        H := I - 1;
        if C = 0 then begin
          Result := True;
          if FList.Duplicates <> dupAccept then L := I;
        end;
      end;
    end;
  end;

基本的に、唯一の実際の変更点は、比較する次のエントリに移動する前にチェックを行うことです。

TStringList からの切り替えはオプションではないことに注意してください。

この方法は機能しますか?

ありがとう

4

1 に答える 1

9

TFilenameUtils.StartsFilenameが同じである場合(そして最初の段落がそうである可能性があることを示唆している場合)、コピーする代わりに使用してStartsText、1 つのステートメントで関数全体を実行できます。 TStringList.Find

var
  I: Integer;
begin
  Assert(not FList.CaseSensitive);
  Result := FList.Find(S, I) or ((I < FList.Count) and StartsText(S, FList[I]));
end;

失敗した場合でも、目的の文字列がFindリストに表示される場所のインデックスが表示されるため、これは機能するはずです。接頭辞文字列を検索すると、その場所はその接頭辞で始まる他の文字列の前になるため、その接頭辞を持つ文字列がある場合、それらは接頭辞自体の仮想の場所の直後に表示されます。


現在のコードを保持したい場合は、 をチェックする条件を削除して単純化できますC = 0StartsFilename関数が壊れていない限り、そのような状態は決して発生しないはずです。ただし、関数が実際に壊れていてゼロになるC 可能性がある場合は、探していたものが見つかったので、少なくともその時点でループの実行を停止できます。いずれにせよ、関数には見つかったアイテムのインデックスを返すのDuplicatesと同じ要件がないため、確認する必要はありません。Find

于 2012-08-16T13:38:07.337 に答える