Delphi-Help

  • Увеличить размер шрифта
  • Default font size
  • Уменьшить размер шрифта

Модуль поиска по маске (более совершенный, нежели дельфийский masks)

Оценить
(0 голоса)

Модуль поиска по маске (более совершенный, нежели дельфийский masks)

unit awMachMask;
interface
 
uses Classes;
 
{Работа со списком шаблонов Функции предназначены
для сопоставления текстов (имен файлов) на соответствие
заданному шаблону или списку шаблонов. Обычно используется
для построения простых фильтров, например аналогичных
файловым фильтрам программы Total Commander. Каждый шаблон
аналогичен шаблону имен файлов в MS-DOS и MS Windows, т.е.
может включать "шаблонные" символы '*' и '?' и не может
включать символ '|'. Любой шаблон может быть заключен в
двойные кавычки ('''), при этом двойные кавычки имеющиеся в
шаблоне должны быть удвоены. Если шаблон включает символы ';'
 или ' ' (пробел) то он обязательно должен быть заключен в
двойные кавычки. В списке, шаблоны разделяются символом ';'.
За первым списком шаблонов, может следовать символ '|', за 
которым может следовать второй список. Текст (имя файла) будет
 считаться соответствующим списку шаблонов только если он 
соответствует хотя бы одному шаблону из первого списка, и 
не соответствует ни одному шаблону из второго списка. Если 
первый список пуст, то подразумевается '*' Формальное описание
синтаксиса списка шаблонов: Полный список шаблонов      :: 
[<список включаемых шаблонов>]['|'<список исключаемых шаблонов>]
список включаемых шаблонов  :: <список шаблонов>
список исключаемых шаблонов :: <список шаблонов>
список шаблонов             :: <шаблон>[';'<шаблон>]
шаблон                      :: шаблон аналогичный шаблону имен файлов в
MS-DOS и MS Windows, т.е. может включать
"шаблонные" символы '*' и '?' и не может
включать символ '|'. Шаблон может быть
заключен в двойные кавычки (''') при этом
двойные кавычки имеющиеся в шаблоне должны
быть удвоены. Если шаблон включает символы
';' или ' ' (пробел) то он
обязательно должен быть заключен в двойные
кавычки.
Например:
'*.ini;*.wav'- соответствует любым файлам с расшиениями 'ini'
или 'wav'
'*.*|*.exe'- соответствует любым файлам, кроме файлов с
расширением 'EXE'
'*.mp3;*.wav|?.*;??.*' - соответствует любым файлам с 
расшиениями 'mp3'
и 'wav' за исключением файлов у которых имя
состоит из одного или двух символов.
'|awString.*'          - соответствует любым файлам за
 исключением файлов
с именем awString и любым расширением.
}
 
Function IsMatchMask (aText, aMask :pChar ) :Boolean; overload;
Function IsMatchMask (aText, aMask :String;
     aFileNameMode :Boolean =True) :Boolean; overload;
//Выполняют сопоставление текста aText с одним шаблоном aMask.
//Возвращает True если сопоставление выполнено успешно, т.е. текст
//aText соответствует шаблону aMask.
//Если aFileNameModd=True, то объект используется для сопоставления
//имен файлов с шаблоном. А именно, в этом случае, если aText не
//содержит символа '.' то он добавляется в конец. Это необходимо для
//того, чтобы файлы без расширений соответствовали например шаблону '*.*'
Function IsMatchMaskList (aText, aMaskList :String;
 aFileNameMode :Boolean =True): Boolean;
  // Выполняет сопоставление текста aText со списком шаблонов aMaskList.
  // Возвращает True если сопоставление выполнено успешно, т.е. текст
  // aText соответствует списку шаблонов aMaskList.
//Если aFileNameModd=True, то объект используется для сопоставления
//имен файлов с шаблоном. А именно, в этом случае, если aText не
//содержит символа '.' то он добавляется в конец. Это необходимо для
//того, чтобы файлы без расширений соответствовали например шаблону '*.*'
//Замечание, если требуется проверка сопоставления нескольких строк одному
//списку шаблонов, эффективнее будет воспользоваться объектом tMatchMaskList.
Type
  tMatchMaskList = class(tObject)
    Private
      fMaskList      :String;
      fCaseSensitive :Boolean;
      fFileNameMode  :Boolean;
 
      fPrepared     :Boolean;
      fIncludeMasks :tStringList;
      fExcludeMasks :tStringList;
 
      procedure SetMaskList      (v :String );
      procedure SetCaseSensitive (v :Boolean);
 
    Public
      constructor Create (Const aMaskList :String ='');
//Создает объект. Если задан параметр aMaskList, то он присваивается
        // свойству MaskList.
 
      destructor  Destroy;    override;
        // Разрушает объект
 
      procedure PrepareMasks;
// Осуществляет компиляцию списка шаблонов во внутреннюю структуру
// используемую при сопоставлении текста.
// Вызов данного метода не является обязательным и при необходимости
// будет вызван автоматически.
 
      Function IsMatch (aText :String) :Boolean;
// Выполняет сопоставление текста aText со списком шаблонов MaskList.
// Возвращает True если сопоставление выполнено успешно, т.е. текст
// aText соответствует списку шаблонов MaskList.
 
      Property MaskList:String   Read fMaskList  Write SetMaskList;
// Списко шаблонов используемый для сопоставления с текстом
 
      Property CaseSensitive :Boolean  Read fCaseSensitive  
 Write SetCaseSensitive   default False;
// Если False (по умолчанию), то при сопоставлении текста будет
// регистр символов не будет учитываться.
// Иначе, если True, сопоставление будет проводиться с учетом регистра.
 
      Property FileNameMode :Boolean   Read fFileNameMode 
   Write fFileNameMode      default True;
// Если True (по умолчанию), то объект используется для сопоставления
// имен файлов с шаблоном. А именно, в этом случае, если aText не
// содержит символа '.' то он добавляется в конец. Это необходимо для
// того, чтобы файлы без расширений соответствовали например шаблону '*.*'
 
    End;
 
 
implementation
 
uses
  SysUtils
 ;
 
Function IsMatchMask (aText, aMask :pChar ) :Boolean;  overload;
begin
  Result := False;
  While  True  Do begin
    Case  aMask^  of
      '*'  :   // соответствует любому числу любых символов кроме конца строки
        begin
          // переместиться на очередной символ шаблона, при этом, подряд
          // идущие '*' эквивалентны одному, поэтому пропуск всех '*'
          repeat  Inc(aMask);  Until  (aMask^<>'*');
          // если за '*' следует любой символ кроме '?' то он должен совпасть
          // с символом в тексте. т.е. нужно пропустить все не совпадающие,
          // но не далее конца строки
          If  aMask^ <> '?'  then
            While  (aText^ <> #0) And (aText^ <> aMask^)  Do  Inc(aText);
 
          If  aText^ <> #0   Then begin  // не конец строки, значит совпал символ
            // '*' 'жадный' шаблон поэтому попробуем отдать совпавший символ
            // ему. т.е. проверить совпадение продолжения строки с шаблоном,
            // начиная с того-же '*'. если продолжение совпадает, то
            If  IsMatchMask (aText+1, aMask-1)  Then  Break;  // это СОВПАДЕНИЕ
            // продолжение не совпало, значит считаем что здесь закончилось
            // соответствие '*'. Продолжим сопоставление со следующего
            // символа шаблона
            Inc(aMask); Inc(aText);     //   иначе переходим к следующему символу
            End
          Else If  (aMask^ = #0)  Then  // конец строки и конец шаблона
            Break                       //     это СОВПАДЕНИЕ
          Else                          // конец строки но не конец шаблона
            Exit                        //     это НЕ СОВПАДЕНИЕ
        End;
 
      '?'  :   // соответствует любому кроме конца строки
        If (aText^ = #0)  Then          // конец строки
          Exit                          //     это НЕ СОВПАДЕНИЕ
        Else begin                      // иначе
          Inc(aMask); Inc(aText);       //   иначе переходим к следующему символу
        End;
 
      Else     // символ в шаблоне должен совпасть с символом в строке
        If  aMask^ <> aText^  Then      // символы не совпали -
          Exit                          //     это НЕ СОВПАДЕНИЕ
        Else begin                      // совпал очередной символ
          If  (aMask^ = #0)  Then       //   совпавший символ последний -
            Break;                      //     это СОВПАДЕНИЕ
          Inc(aMask); Inc(aText);       //   иначе переходим к следующему символу
        End;
    End;
  End;
  Result := True;
End;
 
Function IsMatchMask (aText, aMask :String;
 aFileNameMode :Boolean =True) :Boolean;            overload;
begin
  If  aFileNameMode And (Pos('.',aText)=0)  then  aText := aText+'.';
  Result := IsMatchMask(pChar(aText),pChar(aMask));
End;
 
Function IsMatchMaskList (aText, aMaskList :String;
 aFileNameMode :Boolean =True) :Boolean;
begin
  With  tMatchMaskList.Create(aMaskList)  Do try
    FileNameMode := aFileNameMode;
    Result := IsMatch(aText);
  finally
    Free;
  End;
End;
 
 
/////////////////////////////////////////////////////////// tFileMask
 
 
procedure tMatchMaskList.SetMaskList (v :String );
begin
  If  fMaskList = v  Then  Exit;
  fMaskList := v;
  fPrepared := False;
End;
 
 
procedure tMatchMaskList.SetCaseSensitive  (v :Boolean);
begin
  If  fCaseSensitive = v  Then  Exit;
  fCaseSensitive := v;
  fPrepared      := False;
End;
 
 
constructor tMatchMaskList.Create (Const aMaskList :String);
begin
  MaskList := aMaskList;
  fFileNameMode := True;
 
  fIncludeMasks := TStringList.Create;  With  fIncludeMasks  Do begin
    Delimiter  := ';';
//    Sorted     := True;
//    Duplicates := dupIgnore;
  End;
 
  fExcludeMasks := tStringList.Create;  With  fExcludeMasks  Do begin
    Delimiter  := ';';
//    Sorted     := True;
//    Duplicates := dupIgnore;
  End;
End;
 
 
destructor  tMatchMaskList.Destroy;
begin
  fIncludeMasks.Free;
  fExcludeMasks.Free;
End;
 
 
procedure tMatchMaskList.PrepareMasks;
 
  procedure CleanList(l :tStrings);
  var i :Integer;
  begin
    For  i := l.Count-1  downto  0  Do   If  l[i] = ''  then  l.Delete(i);
  End;
 
var
  s :String;
  i :Integer;
begin
  If  fPrepared  Then  Exit;
 
  If  CaseSensitive  Then
    s := MaskList
  Else
    s := UpperCase(MaskList);
 
  i := Pos('|',s);
  If  i =  0  Then begin
    fIncludeMasks.DelimitedText := s;
    fExcludeMasks.DelimitedText := '';
    End
  Else begin
    fIncludeMasks.DelimitedText := Copy(s,1,i-1);
    fExcludeMasks.DelimitedText := Copy(s,i+1,MaxInt);
  End;
 
  CleanList(fIncludeMasks);
  CleanList(fExcludeMasks);
 
  // если список включаемых шаблонов пуст а
  // список исключаемых шаблонов не пуст, то
  // имеется ввиду что список включаемых шаблонов равен <все файлы>
  If  (fIncludeMasks.Count = 0) And (fExcludeMasks.Count <> 0)  Then
    fIncludeMasks.Add('*');
 
  fPrepared := True;
End;
 
 
Function tMatchMaskList.IsMatch (aText :String) :Boolean;
var
  i :Integer;
begin
  Result := False;
  If  aText = ''  then  Exit;
  If  Not CaseSensitive  Then  aText := UpperCase(aText);
  If  FileNameMode And (Pos('.',aText)=0)  then  aText := aText+'.';
  If  Not fPrepared  Then  PrepareMasks;
 
  // поиск в списке "включаемых" масок до первого совпадения
  For  i := 0  To  fIncludeMasks.Count-1  Do
    If  IsMatchMask(PChar(aText),PChar(fIncludeMasks[i]))  Then begin
      Result := True;
      Break;
    End;
 
  // если совпадение найдено, надо проверить по списку "исключаемых"
  If  Result  Then
    For  i := 0  To  fExcludeMasks.Count-1  Do
      If  IsMatchMask(PChar(aText),PChar(fExcludeMasks[i]))  Then begin
        Result := False;
        Break;
      End;
End;
 
 
 
end.

 

Login to post comments

Счетчики