跳转到内容

Ada 编程/字符串

来自维基教科书,开放的书籍,开放的世界

Ada. Time-tested, safe and secure.
Ada。经久耐用,安全可靠。

Ada 支持三种不同的字符串类型。每种字符串类型旨在解决不同的问题。

此外,每种字符串类型都针对每种可用的字符类型 (Character, Wide_Character, Wide_Wide_Character) 实现,共计九种组合。

固定长度字符串处理

[编辑 | 编辑源代码]

固定长度字符串(预定义类型 String)是 字符数组,因此长度固定。由于 String 是一个 不确定的子类型,因此长度不需要在编译时知道 - 长度可以在运行时计算出来。在以下示例中,长度是从命令行参数 1 计算出来的

X : String := Ada.Command_Line.Argument (1);

但是,一旦长度被计算出来并且字符串被创建,长度将保持不变。尝试以下程序,它展示了一个典型的错误

文件:show_commandline_1.adb (查看纯文本下载页面浏览所有)
with Ada.Text_IO;
with Ada.Command_Line;

procedure Show_Commandline_1 is

   package T_IO renames Ada.Text_IO;
   package CL   renames Ada.Command_Line;

   X : String := CL.Argument (1);

begin
   T_IO.Put ("Argument 1 = ");
   T_IO.Put_Line (X);

   X := CL.Argument (2);

   T_IO.Put ("Argument 2 = ");
   T_IO.Put_Line (X);
end Show_Commandline_1;

该程序仅当第 1 个和第 2 个参数具有相同的长度时才有效。即使第 2 个参数更短,情况也是如此。没有对较短字符串的自动填充,也没有对较长字符串的自动截断。

话虽如此,包 Ada.Strings.Fixed 包含一组用于固定长度字符串处理的程序和函数,允许填充较短字符串和截断较长字符串。

尝试以下示例以查看其工作原理

文件:show_commandline_2.adb (查看纯文本下载页面浏览所有)
with Ada.Text_IO;
with Ada.Command_Line;
with Ada.Strings.Fixed;

procedure Show_Commandline_2 is

   package T_IO renames Ada.Text_IO;
   package CL   renames Ada.Command_Line;
   package S    renames Ada.Strings;
   package SF   renames Ada.Strings.Fixed;

   X : String := CL.Argument (1);

begin
   T_IO.Put ("Argument 1 = ");
   T_IO.Put_Line (X);

   SF.Move (
     Source  => CL.Argument (2),
     Target  => X,
     Drop    => S.Right,
     Justify => S.Left,
     Pad     => S.Space);

   T_IO.Put ("Argument 2 = ");
   T_IO.Put_Line (X);
end Show_Commandline_2;

有界长度字符串处理

[编辑 | 编辑源代码]

当已知和/或限制字符串的最大长度时,可以使用有界长度字符串。这在数据库应用程序中很常见,在数据库应用程序中,只能存储有限数量的字符。

与固定长度字符串一样,最大长度不需要在编译时知道 - 它也可以在运行时计算出来 - 如下面的示例所示

文件:show_commandline_3.adb (查看纯文本下载页面浏览所有)
with Ada.Text_IO;
with Ada.Command_Line;
with Ada.Strings.Bounded;

procedure Show_Commandline_3 is

   package T_IO renames Ada.Text_IO;
   package CL   renames Ada.Command_Line;

   function Max_Length (
      Value_1 : Integer;
      Value_2 : Integer)
   return
      Integer
   is
      Retval : Integer;
   begin
      if Value_1 > Value_2 then
         Retval := Value_1;
      else
         Retval := Value_2;
      end if;
      return Retval;
   end Max_Length;

   pragma Inline (Max_Length);

   package SB
   is new Ada.Strings.Bounded.Generic_Bounded_Length (
       Max => Max_Length (
                  Value_1 => CL.Argument (1)'Length,
                  Value_2 => CL.Argument (2)'Length));

   X :  SB.Bounded_String
     := SB.To_Bounded_String (CL.Argument (1));

begin
   T_IO.Put ("Argument 1 = ");
   T_IO.Put_Line (SB.To_String (X));

   X := SB.To_Bounded_String (CL.Argument (2));

   T_IO.Put ("Argument 2 = ");
   T_IO.Put_Line (SB.To_String (X));
end Show_Commandline_3;

您应该知道,有界长度字符串有一些明显的缺点。最明显的是,每个有界长度字符串都是一个不同的类型,这使得转换它们相当麻烦。此外,有界长度字符串类型始终为类型允许的最大字符串长度分配内存。有界长度字符串的内存分配等于最大字符串“字符”数加上一个实现相关的数字,其中包含字符串长度(每个字符可能需要分配超过一个字节的字符,具体取决于字符串的底层字符类型,而长度数字对于 Windows GNAT Ada 编译器 v3.15p 来说是 4 个字节,例如)。

无界长度字符串处理

[编辑 | 编辑源代码]

最后但并非最不重要的是无界长度字符串。事实上:如果您没有进行嵌入式或数据库编程,这将是您最常使用的字符串类型,因为它为您提供了最大的灵活性。

顾名思义,无界长度字符串可以保存几乎任何长度的字符串 - 仅限于 Integer'Last 的值或您的可用堆内存。这是因为 Unbounded_String 类型在幕后使用动态内存分配,提供较低的效率但最大的灵活性。

文件:show_commandline_4.adb (查看纯文本下载页面浏览所有)
with Ada.Text_IO;
with Ada.Command_Line;
with Ada.Strings.Unbounded;

procedure Show_Commandline_4 is

   package T_IO renames Ada.Text_IO;
   package CL   renames Ada.Command_Line;
   package SU   renames Ada.Strings.Unbounded;

   X :  SU.Unbounded_String 
     := SU.To_Unbounded_String (CL.Argument (1));

begin
   T_IO.Put ("Argument 1 = ");
   T_IO.Put_Line (SU.To_String (X));

   X := SU.To_Unbounded_String (CL.Argument (2));

   T_IO.Put ("Argument 2 = ");
   T_IO.Put_Line (SU.To_String (X));
end Show_Commandline_4;

如您所见,无界长度字符串示例也是最短的 (不考虑有错误的第一个示例) - 这使得使用无界长度字符串非常吸引人。

另请参阅

[编辑 | 编辑源代码]

维基教科书

[编辑 | 编辑源代码]

Ada 95 参考手册

[编辑 | 编辑源代码]

Ada 2005 参考手册

[编辑 | 编辑源代码]
华夏公益教科书