2015-01-29 2 views
3

Я пытаюсь создать функцию, которая может увеличивать имя файла. Если последний символ строки является числом, то увеличивайте его. Если последний символ - это буква, то добавьте _1 или _2 или _3 (добавьте это также). Я должен быть уверен, что имя файла уникально, но я не могу использовать datetime внутри filename, потому что все имена файлов должны быть < 32 символа без расширения.Функция для увеличения файла filename

EX: Apple_99.txt =>Apple_100 
Ex: Apple_173 => Apple_174 
EX: This_is_my_first_text.txt => This_is_my_first_text_1.txt 
Ex: This_is_my_first_text_9.txt => This_is_my_first_text_10.txt 

Мне нужно использовать это, чтобы переименовать файл, а затем загрузить его на ftp-сервер. Я нашел функцию, которая может сделать что-то вроде этого, но она работает только в том случае, если имя файла содержит только верхний регистр. Как я могу изменить эту функцию, чтобы получить доступ к строчной строке в верхнем регистре?

Вот функция:

function IncStr(Str: String; Amount: Integer; Index: Integer = -1): String; 
    const 
    MIN_VAL = 65; // 'A' 
    MAX_VAL = 90; // 'Z' 
    var 
    Digit, ToAdd, ToCarry: Integer; 
    begin 

    if (Index = 0) and (Amount > 0) then 
     begin 
     Result := Char(MIN_VAL + Amount - 1) + Str; 
     Exit; 
     end; 

    if Index = -1 then Index := Length(Str); 

    ToCarry := 0; 

    Digit := Ord(Str[Index]); 

    while not (Digit in [MIN_VAL..MAX_VAL]) do 
     begin 
     Dec(Index); 
     Digit := Ord(Str[Index]); 
     end; 

    ToAdd := Digit + Amount; 

    while (ToAdd > MAX_VAL) do 
     begin 
     Dec(ToAdd, 26); 
     Inc(ToCarry); 
     end; 

    Result := Str; 
    Result[Index] := Char(ToAdd); 

    if (ToCarry > 0) then 
     Result := IncStr(Result, ToCarry, Index - 1); 

    end; 


    procedure TForm1.Button1Click(Sender: TObject); 
    var 
    S: String; // holds string to increment 
    C: Integer; // amount to increment by 
    begin 
    // make sure that Edit1 starts with a valid character 
    // i.e. 'A' to 'Z' 
    S := Edit1.Text; 
    C := StrtoIntDef(Edit2.Text, 0); 
    // test it, place result in Edit3 
    Edit3.Text := IncStr(S, C); 
    { 
     Example data: 

     Edit1 := AAZ 
     Edit2 := 2 
     = Edit3 := ABB 

     Edit1 := BZY 
     Edit2 := 3 
     = Edit3 := CAB 

     Edit1 := ZZZ 
     Edit2 := 1 
     = Edit3 := AAAA 

     Edit1 := AA-AC 
     Edit2 := 3 
     = Edit3 := AA-AF 

     Edit1 := AA/Z 
     Edit2 := 5 
     = Edit3 := AB/E 

     ... etc 

     Here's one to try too :-) 
     Edit1 := ZZZ 
     Edit2 := 264172 
    } 
    end; 

Спасибо!

ответ

5

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

procedure DecodeFileName(const Input: string; out Stem, Ext: string; out Number: Integer); 
var 
    P: Integer; 
begin 
    Ext := TPath.GetExtension(Input); 
    Stem := TPath.GetFileNameWithoutExtension(Input); 
    Number := 0; 

    P := Stem.LastIndexOf('_'); 
    if P = -1 then begin 
    exit; 
    end; 

    if TryStrToInt(Stem.Substring(P+1), Number) then begin 
    Stem := Stem.Substring(0, P); 
    end; 
end; 

Ниже показано, как это работает:

DecodeFileName('test.txt', Stem, Ext, Number); 
Writeln(Stem, ', ', Number, ', ', Ext); 

DecodeFileName('test_dd.txt', Stem, Ext, Number); 
Writeln(Stem, ', ', Number, ', ', Ext); 

DecodeFileName('test_23.txt', Stem, Ext, Number); 
Writeln(Stem, ', ', Number, ', ', Ext); 

Выход:

 
test, 0, .txt 
test_dd, 0, .txt 
test, 23, .txt 

Итак, вы можете создать новое имя файла:

function IncrementedFileName(const FileName: string): string; 
var 
    Stem, Ext: string; 
    Number: Integer; 
begin 
    DecodeFileName(FileName, Stem, Ext, Number); 
    Result := Format('%s_%d%s', [Stem, Number+1, Ext]); 
end; 

И тогда мы можем видеть, как это работает:

Writeln(IncrementedFileName('test.txt')); 
Writeln(IncrementedFileName('test_dd.txt')); 
Writeln(IncrementedFileName('test_23.txt')); 
Writeln(IncrementedFileName('test_28')); 

Выход:

 
test_1.txt 
test_dd_1.txt 
test_24.txt 
test_29 

Если у вас нет доступа к методам строки хелперов, то вы можете написать это так:

procedure DecodeFileName(const Input: string; out Stem, Ext: string; out Number: Integer); 
var 
    P: Integer; 
begin 
    Ext := TPath.GetExtension(Input); 
    Stem := TPath.GetFileNameWithoutExtension(Input); 
    Number := 0; 

    P := LastDelimiter('_', Stem); 
    if P = 0 then begin 
    exit; 
    end; 

    if TryStrToInt(Copy(Stem, P+1, MaxInt), Number) then begin 
    Stem := Copy(Stem, 1, P-1); 
    end; 
end; 

Я не выполнил эту окончательную функцию, поэтому не удивляйтесь, если у нее есть ошибки.

+0

Спасибо, Дэвид. Ты такой быстрый. Просто небольшая проблема: я не пишу консольное приложение, поэтому Delphi 2010 показывает мне некоторые ошибки: строка не содержит члена с именем «LastIndexof» (stem.lastindexof), строка не содержит члена с именем «подстрока» (строка .substring). Я уже добавил, что ioutils использует список. Большое спасибо – user2858981

+1

@ user2858981 Используя решение Дэвида - это здорово, поскольку это так просто - вы должны заверить, что возвращаемое имя файла еще не существует. Вы можете архивировать это, вызывая его в цикле while: 'while FileExists (MyFileName) do MyFileName: = IncrementedFileName (MyFileName);' –

+0

Вы не указываете версию Delphi в вопросе. Я предположил более современную версию. Используйте LastDelimiter вместо LastIndexOf. И Скопировать вместо подстроки. Обе эти функции - это функции, а не методы. –

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