2016-06-26 5 views
0

Мне нужно удалить все файлы, имена которых начинаются с «a», а затем три произвольные буквы и расширение «.txt», например «a123.txt». Вот код:FindFirst и вопросительный знак

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»?

ответ

4

Самое простое решение для ваших конкретных потребностей, чтобы заменить это:

ShowMessage(tsrMessage.Name); 

с этим

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

это гарантирует, что длина имени файла ровно четыре символа + период + расширение. Как говорит Дэвид, нет никакого способа, чтобы API выполнял такую ​​фильтрацию, поэтому вам придется делать это самостоятельно, но в вашем конкретном случае нет необходимости перечислять весь каталог. Вы можете, по крайней мере, разрешить API делать фильтрацию , а сделать, а затем сделать свою собственную фильтрацию поверх нее.

EDIT: Если вам необходимо убедиться, что три символа после «а» являются цифры, вы можете сделать это следующим образом:

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

Да, я также хотел использовать этот метод, но пример, который я использовал, был упрощен. На самом деле мне нужно удалить файлы в соответствии с маской, как в формате, таком как% 03d.txt и т. Д. В этом случае код становится слишком сложным для такой простой задачи, поэтому я решил, что я делаю что-то неправильно. – Molochnik

+0

@Molochnik: Смотрите раздел EDIT ... – HeartWare

4

Такое поведение, как и предусмотрено. Это объясняется Раймондом Ченом здесь: How did wildcards work in MS-DOS?

Вы увидите то же самое поведение в командном интерпретаторе.

 
C:\Desktop>dir a???.txt 
Volume in drive C has no label. 
Volume Serial Number is 20DA-7FEB 

Directory of 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 File(s)    24 bytes 
       0 Dir(s) 286,381,445,120 bytes free 

Там нет никакого способа, чтобы убедить FindFirstFile (в API, который находится за РТЛ-х FindFirst на Windows), чтобы вести себя так, как вы хотите. Ваш лучший вариант - перечислить весь каталог и выполнить собственную фильтрацию, используя выбранный вами алгоритм сопоставления шаблонов.

+0

Спасибо, получил его, это было давно, так как я в последний раз использовал этот подстановочные, так что я был 100% уверен, что «?» означает ровно один символ. – Molochnik

+0

@Molochnik Подстановочный знак одного символа в SQL работает, как вы описываете - возможно, именно здесь происходит ваше замешательство. Его поймали меня раньше. С уважением, –

+0

@ Майкл. Да, это возможно, но маловероятно, что в течение десятилетия я использую нотацию с регулярными выражениями (раньше я использовал fnmatch), и мне не приходило в голову, что все еще существуют постоянные члены без подстановочного знака, что означает одиночный знак. – Molochnik

Смежные вопросы