Как я могу создать функцию с произвольным количеством параметров? - PullRequest
0 голосов
/ 27 ноября 2011

Я хочу создать функцию, которая получает несколько строк в качестве параметров.Как и функция printf("Hello %s",name); из C., но я не хочу передавать готовый массив, он не будет доступен для чтения.

Edit1.text:=lang('Hello');

Edit2.text:=lang('Welcome to {1} guest',place);

Edit3.text:=lang('Hi {1}, is your {2} time in {3}','Victor','first','Disney');

вывод должен быть:

Hello
Welcome to Disney guest
Hi Victor is your first time in Disney

как я создал function TForm1.lang(parameters:String):String;, я провел исследование, но я не могу заставить его работать.

Мне нужен также доступ к параметрам [] и параметрам. длина.

IМне нужно, чтобы превратить мое приложение в многоязычное.

Ответы [ 6 ]

4 голосов
/ 27 ноября 2011

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

function TForm1.lang(s: String; params: array of String): String;
var
  i: Integer;
begin
  for i := 0 to High(params) do
  begin
    ShowMessage(params[i]);
  end;
end;

Назовите это так:

lang('My format string', ['this', 'that']);

или как это:

var
  b: String;
begin
  b := 'this';
  lang('My format string', [b, 'that']);
end;
3 голосов
/ 27 ноября 2011

Не уверен, что вы подразумеваете под нечитабельным

DoSomething(['Param1','Param2']);

для

procedure DoSomething(args : Array of String);
Var
  Index : Integer;
Begin
  for index := Low(args) to High(args) Do
    ShowMessage(args[Index]);
End;

Кажется, все в порядке для меня.Конечно, если вы хотите позвонить из-за пределов delphi, у вас есть проблема.

Быстрое исправление - это просто передать строку с разделителями и затем использовать TStringList для ее разделения.

Вы можете написать для этого небольшую функцию, не забудьте освободить ее, когда высделано.

1 голос
/ 27 ноября 2011

Delphi не поддерживает функции CREATING с параметрами стиля vararg, которые работают точно так же, как printf(). Он поддерживает только ПОТРЕБЛЕНИЕ таких функций из внешних библиотек. Самое близкое Delphi к поддержке создания функций с переменными списками параметров - это использование параметров «открытого массива», как то, что использует SysUtils.Format().

1 голос
/ 27 ноября 2011

Все три примера можно исправить с помощью SysUtils.Format:

Edit1.text := format('%s',['Hello']));
Edit1.text := format('Welcome to %s guest',[place]));
Edit1.text := format('Hi %s, is your %s time in %s',['Victor','first','Disney']));

Лично я думаю, что это вполне читабельно. Если вы можете получить то, что вам нужно от базовой функции sysutils, вам следует серьезно подумать об этом, а не писать свою собственную версию. С другой стороны, вам может потребоваться более сложная функциональность, которая не отражена в вашем вопросе. Если это так, я думаю, что предложение paulsm4 об использовании stringlist кажется хорошим вариантом.

0 голосов
/ 27 ноября 2011

Как Тони упоминает выше, я также рекомендую использовать исключенную строку.За исключением, немного больше, чем просто устранение, но использование большего количества техники разбора.Если я правильно понимаю, эта функция, которую вы делаете для форматирования, НЕ должна включать массив в параметры, но технически это не означает, что мы нигде не можем использовать массивы (массивы идеально подходят для этого сценария длявысокая производительность).

Этот метод позволяет передавать в параметры практически все, включая разделитель, без влияния на вывод.Идея состоит в том, чтобы сделать A) Размер строки параметра, B) Разделитель между размером и параметром и C) Строка параметра ... И повторить ...

const
  MY_DELIM = '|';  //Define a deliminator

type
  TStringArray = array of String;

/////////////////////////////////

//Convert an array of string to a single parsable string
//  (Will be the first step before calling your format function)
function MakeParams(const Params: array of String): String;
var
  X: Integer;
  S: String;
begin
  Result:= '';
  for X:= 0 to Length(Params)-1 do begin
    S:= Params[X];
    Result:= Result + IntToStr(Length(S)) + MY_DELIM + S;
  end;
end;

//Convert a single parsable string to an array of string
//  (Will be called inside your format function to decode)
//  This is more or less called parsing
function ExtractParams(const Params: String): TStringArray;
var
  S: String;  //Used for temporary parsing
  T: String;  //Used for copying temporary data from string
  P: Integer; //Used for finding positions
  C: Integer; //Used for keeping track of param count
  Z: Integer; //Used for keeping track of parameter sizes
begin
  S:= Params;                   //Because we'll be using 'Delete' command
  C:= 0;                        //Set count to 0 to start
  SetLength(Result, 0);         //Prepare result array to 0 parameters
  while Length(S) > 0 do begin  //Do loop until nothing's left
    P:= Pos(MY_DELIM, S);       //Get position of next deliminator
    if P > 1 then begin         //If deliminator was found...       
      C:= C + 1;                  //We have a new parameter
      SetLength(Result, C);       //Set array length to new parameter count
      T:= Copy(S, 1, P-1);        //Get all text up to where deliminator was found
      Delete(S, 1, P);            //Delete what we just copied, including deliminator
      Z:= StrToIntDef(T, 0);      //Convert T:String to Z: Integer for size of parameter
      T:= Copy(S, 1, Z);          //Get all text up to 'Z' (size of parameter)
      Delete(S, 1, Z);            //Delete what we just copied
      Result[C-1]:= T;              //Assign the new parameter to end of array result
    end else begin              //If deliminator was NOT found...
      S:= '';                     //Clear S to exit loop (possible bad format if this happens)
    end;
  end;
end;

//Main formatting routine
function MyFormat(const Input: String; const Params: String): String;
var
  A: TStringArray;
  X: Integer;
  S: String;
  P: Integer;
  R: String;
begin
  R:= Input;
  A:= ExtractParams(Params);
  //At this point, A contains all the parameters parsed from 'Params'
  for X:= 0 to Length(A)-1 do begin
    S:= A[X];
    P:= Pos('%s', R);
    if P > 0 then begin
      Delete(R, P, 2);
      Insert(S, R, P);
    end;
  end;
  Result:= R;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Pars: String;
begin
  Pars:= MakeParams(['this', 'that', 'something else']);
  Edit1.Text:= MyFormat('%s is %s but not %s', Pars);
end;
0 голосов
/ 27 ноября 2011

Как вы, наверное, знаете, SysUtils.Format () реализует "varargs" с помощью набора.

В вашем случае, однако, почему бы просто не передать TStringList? Функция просто проверит «list.Count». Вуаля - все готово!

...