Comment construire une chaîne à partir d'autres chaînes d'Ada?
Question
Je souhaite sortir une ligne d'en-tête dans un fichier journal puis une ligne de '-' avant les données. Pour ce faire, je crée une chaîne de l'en-tête, puis je dépasse le même nombre de '-'.
Mais le code ci-dessous échoue toujours avec une CONSTRAINT_ERROR car la chaîne générée n'est pas 1024 caractères. Dans ADA, les affectations de chaînes nécessitent exactement la même longueur et non seulement une capacité suffisante.
L'option 1) est de calculer la longueur exacte, mais cela est fragile pour les changements futurs. L'option 2) consiste à utiliser autre chose que la chaîne.
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;
La solution
Beaucoup de gens qui sont habitués à la manière C de construire des cordes en pas ont du mal à enrouler leur esprit autour des cordes ADA, qui vous êtes censé initialiser et utiliser tel quel. Lorsque vous approchez ce fait sur les cordes ADA, la solution devient beaucoup plus simple. Je peux même jeter votre routine de "remplissage".
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;
(Remarque: le commentaire est un piratage pour récupérer le coloriseur de So sur la bonne voie)
Si vous n'aviez pas besoin d'avoir le séparateur de la même longueur, vous n'auriez même pas besoin de déclarer la variable.
Si c'était moi, je ferais quelque chose comme Log_To_File
Gardez une trace des longueurs et générez son propre séparateur de bonne taille sur demande. Ensuite, vous pouvez simplement écrire:
Open_Log();
Log_To_File ("# " & FLS(" Field1", 12) &
"|" & FLS(" Field2", 12) &
"|" & FLS(" Field3", 16));
Log_Separator_To_File;
Autres conseils
Déclarez simplement MSG comme une chaîne au lieu d'une chaîne (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;
Une approche pourrait être d'écrire une fonction qui remplit une chaîne de longueur fixe avec une chaîne d'entrée de taille dynamiquement, un rembourrage avec des espaces:
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;
La gestion des cordes d'Ada vous permet de passer n'importe quel tampon de longueur fixe dans Dest
et le 'First
et 'Last
Les attributs seront corrects dans le corps de la procédure.
Ensuite, votre code pourrait devenir:
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;
Comme commodité, vous pouvez utiliser les fonctions du constructeur de chaînes dans Ada.Strings.Fixed
, Ada.Strings.Bounded
ou Ada.Strings.Unbounded
. Ceux-ci surchargent l'opérateur * pour "reproduire un caractère ou une chaîne un nombre de fois spécifié". Par exemple,
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
...
Log_To_File("# " & Length(Msg) * '-');
J'ai travaillé comment utiliser un peu lié_string. Ce type acceptera d'autres chaînes de taille.
Vous ne pouvez pas construire une chaîne non liée avec l'opérateur à moins que vous n'utilisiez des chaînes non liées, alors utilisez la fonction TO_UNBOUNDED_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;