如何在 Ada 中从其他字符串构建字符串?

发布于 2024-08-21 17:12:17 字数 540 浏览 10 评论 0原文

我想在日志文件中输出标题行,然后在数据之前输出一行“-”。为此,我创建了一个标题字符串,然后输出相同数量的“-”。

但下面的代码总是失败并出现 CONSTRAINT_ERROR,因为生成的字符串不是 1024 个字符。在 Ada 中,字符串赋值需要完全相同的长度,而不仅仅是足够的容量。

选项 1) 是计算精确的长度,但这对于未来的更改来说很脆弱。 选项 2) 是使用 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;

I want to output a header line in a log file and then a line of '-' before the data. To do this I create a string of the header and then outpout the same number of '-'.

But the below code always fails with a CONSTRAINT_ERROR because the generated string is not 1024 characters. In Ada string assignments require exactly the same length not just sufficient capacity.

Option 1) is to compute the exact length but that is brittle to future changes.
Option 2) is to use something other than 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;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

国粹 2024-08-28 17:12:17

许多习惯使用 C 方法逐步构建字符串的人很难理解 Ada 字符串,而您应该按原样初始化并使用 Ada 字符串。当您了解 Ada 字符串的这一事实时,解决方案就会变得简单得多。我什至可以抛弃你的“填充”例程。

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;

(注意:该评论是让 SO 的着色器回到正轨的一种技巧)

如果您不必使分隔符具有相同的长度,您甚至不需要声明变量。

如果是我,我会做类似让 Log_To_File 跟踪长度并根据请求生成其自己的适当大小的分隔符的操作。然后你可以这样写:

Open_Log();
Log_To_File ("# " & FLS(" Field1", 12) & 
       "|" & FLS(" Field2", 12) & 
       "|" & FLS(" Field3", 16)); 
Log_Separator_To_File;

A lot of folks who are used to the C way of building strings in steps have trouble wrapping their minds around Ada strings, which you are supposed to initialize and use as-is. When you grok this fact about Ada strings, the solution becomes much simpler. I can even throw out your "Fill" routine.

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;

(Note: The comment is a hack to get SO's colorizer back on track)

If you didn't have to have the separator the same length, you wouldn't even need to declare the variable.

If it were me, I'd do something like have Log_To_File keep track of lengths and generate its own properly-sized separator upon request. Then you could just write:

Open_Log();
Log_To_File ("# " & FLS(" Field1", 12) & 
       "|" & FLS(" Field2", 12) & 
       "|" & FLS(" Field3", 16)); 
Log_Separator_To_File;
哭了丶谁疼 2024-08-28 17:12:17

只需将 Msg 声明为 String 而不是 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;

Just declare Msg as a String instead of a 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;
楠木可依 2024-08-28 17:12:17

一种方法可能是编写一个函数,用动态大小的输入字符串填充固定长度字符串,并用空格填充:

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;

Ada 的字符串处理允许您将任何固定长度缓冲区传递到 Dest'First'Last 属性在过程体内是正确的。

然后,你的代码可能会变成:

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;    

One approach might be to write a function that fills a fixed length string with a dynamically sized input string, padding with spaces:

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;

Ada's string handling allows you to pass any fixed length buffer into Dest and the 'First and 'Last attributes will be correct within the body of the procedure.

Then, your code could become:

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;    
快乐很简单 2024-08-28 17:12:17

为了方便起见,您可以使用 中的 String 构造函数Ada.Strings.FixedAda.Strings.BoundedAda.Strings.Unbounded。这些重载 * 运算符以“将字符或字符串复制指定的次数”。例如,

with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
   ...
   Log_To_File("# " & Length(Msg) * '-');

As a convenience, you can use the String constructor functions in Ada.Strings.Fixed, Ada.Strings.Bounded or Ada.Strings.Unbounded. These overload the * operator to "replicate a character or string a specified number of times." For example,

with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
   ...
   Log_To_File("# " & Length(Msg) * '-');
ペ泪落弦音 2024-08-28 17:12:17

我弄清楚了如何使用 Unbounded_String。该类型将接受其他大小的字符串。

您无法使用 & 构建无界字符串。运算符,除非您使用无界字符串,否则请使用 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; 

I worked out how to use Unbounded_String. That type will accept other sized strings.

You can't build an unbounded string with the & operator unless you are using unbounded strings so use the To_Unbounded_String function.

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; 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文