Como eu construir uma corda de outras cordas em Ada?
Pergunta
Quero emitir uma linha de cabeçalho em um arquivo de log e, em seguida, uma linha de '-' antes dos dados. Para fazer isso, crio uma sequência do cabeçalho e depois supere o mesmo número de '-'.
Mas o código abaixo sempre falha com uma restrição_error porque a string gerada não tem 1024 caracteres. Nas atribuições de string da ADA requerem exatamente o mesmo comprimento, não apenas capacidade suficiente.
A opção 1) é calcular o comprimento exato, mas isso é quebradiço para mudanças futuras. A opção 2) é usar algo diferente da string.
procedure F() is
Msg : String(1..1024);
begin
Open_Log();
Msg := FLS(" Field1", 12) &
"|" & FLS(" Field2", 12) &
"|" & FLS(" Field3", 16);
Log_To_File("# " & Msg);
Log_To_File("# " & Fill_String(Msg'Last, '-'));
end;
Solução
Muitas pessoas que estão acostumadas com a maneira C de construir cordas em etapas têm problemas para envolver suas mentes em torno de Strings Ada, que você deveria inicializar e usar como está. Quando você obtém esse fato sobre as cordas da ADA, a solução se torna muito mais simples. Eu posso até jogar fora sua rotina de "preenchimento".
procedure F() is
Msg : constant String
:= FLS(" Field1", 12) &
"|" & FLS(" Field2", 12) &
"|" & FLS(" Field3", 16);
Separator : constant String := (1..Msg'length => '-'); --'
begin
Open_Log();
Log_To_File("# " & Msg);
Log_To_File("# " & Separator);
end;
(Nota: o comentário é um hack para recuperar o colorizer de So na pista)
Se você não precisasse ter o separador da mesma duração, nem precisaria declarar a variável.
Se fosse eu, eu faria algo como ter Log_To_File
Acompanhe os comprimentos e gerar seu próprio separador de tamanho adequado mediante solicitação. Então você pode apenas escrever:
Open_Log();
Log_To_File ("# " & FLS(" Field1", 12) &
"|" & FLS(" Field2", 12) &
"|" & FLS(" Field3", 16));
Log_Separator_To_File;
Outras dicas
Basta declarar o msg como uma string em vez de uma string (1 .. 1024)
procedure F() is
Msg: String
:= FLS(" Field1", 12) &
"|" & FLS(" Field2", 12) &
"|" & FLS(" Field3", 16);
--// this 'magically' declares Msg as a String(1 .. Something)
--// with the right Something
begin
Open_Log();
Log_To_File("# " & Msg);
Log_To_File("# " & Fill_String(Msg'Last, '-')); --'
end;
Uma abordagem pode ser escrever uma função que preencha uma string de comprimento fixo com uma string de entrada de tamanho dinâmico, preenchendo com espaços:
procedure Pad_String(Str: in String; Dest: out String; Len: out Integer) is
begin
Len := Str'Last - Str'First + 1;
Dest(Dest'First .. Dest'First + Len - 1) := Str(Str'First .. Str'First + Len - 1);
Dest(Dest'First + Len .. Dest'Last) := Fill_String(Dest'Last - Len, ' ');
end Pad_String;
O manuseio de string da ADA permite que você passe qualquer buffer de comprimento fixo para Dest
e a 'First
e 'Last
Os atributos estarão corretos dentro do corpo do procedimento.
Então, seu código pode se tornar:
procedure F() is
Msg : String(1..1024);
Len : Integer;
begin
Open_Log();
Pad_String( FLS(" Field1", 12) &
"|" & FLS(" Field2", 12) &
"|" & FLS(" Field3", 16),
Msg,
Len);
Log_To_File("# " & Msg(1 .. Len));
Log_To_File("# " & Fill_String(Len, '-'));
end;
Como conveniência, você pode usar as funções do construtor de strings em Ada.Strings.Fixed
, Ada.Strings.Bounded
ou Ada.Strings.Unbounded
. Estes sobrecarregar o operador * para "replicar um caractere ou string um número especificado de vezes". Por exemplo,
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
...
Log_To_File("# " & Length(Msg) * '-');
Eu calculei como usar o Unbored_String. Esse tipo aceitará outras cordas de tamanho.
Você não pode construir uma string ilimitada com o Operador, a menos que esteja usando strings ilimitados; portanto, use a função TO_UNBOUND_STRING.
with Ada.Strings.Unbounded;
procedure F() is
use Ada.Strings.Unbounded;
Msg : Unbounded_String;
begin
Open_Log();
Msg := Ada.Strings.Unbounded.To_Unbounded_String(
FLS(" Field1", 12) &
"|" & FLS(" Field2", 12) &
"|" & FLS(" Field3", 16));
Log_To_File("# " & Ada.Strings.Unbounded.To_String(Msg));
Log_To_File("# " &
Fill_String(Ada.Strings.Unbounded.Length(Msg), '-'));
end;