3

我正在尝试编写一个等效于 Java 或 C++ 中的 split() 方法的 Ada。我要输入一个字符串和一个整数并输出两个单独的字符串值。例如:拆分“hello”和 2 将返回:“第一部分是 he,第二部分是 llo”

我的代码如下:

-- split.adb splits an input string about a specified position.
--
-- Input: Astring, a string,
--        Pos, an integer.
-- Precondition: pos is in Astring'Range.
-- Output: The substrings Astring(Astring'First..Pos) and
--                        Astring(Pos+1..Astring'Last).
--------------------------------------------------------------

with Ada.Text_IO, Ada.Integer_Text_IO, Ada.Strings.Fixed;
use  Ada.Text_IO, Ada.Integer_Text_IO, Ada.Strings.Fixed;

procedure Split is

   EMPTY_STRING : String := "                                        ";

   Astring, Part1, Part2 : String := EMPTY_STRING;
   Pos, Chars_Read       : Natural;

   ------------------------------------------------
   -- Split() splits a string in two.           
   -- Receive: The_String, the string to be split,
   --          Position, the split index.        
   -- PRE: 0 < Position <= The_String.length(). 
   --     (Ada arrays are 1-relative by default)
   -- Passback: First_Part - the first substring,
   --           Last_Part - the second substring.
   ------------------------------------------------
   function Split(TheString : in String ; Pos : in Integer; Part1 : out String ; Part2     : out String)  return String is 
   begin
    Move(TheString(TheString'First .. Pos), Part1);
    Move(TheString(Pos .. TheString'Last), Part2);
    return Part1, Part2;
     end Split;



begin                                           -- Prompt for input
   Put("To split a string, enter the string: ");
   Get_Line(Astring, Chars_Read);
   Put("Enter the split position: ");
   Get(Pos);

   Split(Astring, Pos, Part1, Part2);

   Put("The first part is ");
   Put_Line(Part1);
   Put(" and the second part is ");
   Put_Line(Part2);

end Split;

我遇到问题的主要部分是返回两个单独的字符串值,通常是整个 split() 函数。任何指针或帮助表示赞赏。谢谢

4

6 回答 6

4

如您所展示的function,考虑使Splitaprocedure具有两个参数,而不是 a 。out然后判断Pos是 的最后一个索引Part1还是 的第一个索引Part2;我选择了后者。

procedure Split(
   TheString : in String; Pos : in Integer;
   Part1 : out String; Part2 : out String) is 
begin
   Move(TheString(TheString'First .. Pos - 1), Part1);
   Move(TheString(Pos .. TheString'Last), Part2);
end Split;

请注意,String索引是Positive

type String is array(Positive range <>) of Character;
subtype Positive is Integer range 1 .. Integer'Last;
于 2013-02-20T02:57:27.940 回答
4

这样做是如此微不足道,我不确定你为什么要为它制定一个例程。无论如何,几乎任何你能想出的例程都将变得更难使用。

Front_Half : constant String := Original(Original'first..Index);
Back_Half  : constant String := Original(Index+1..Original'last);

完毕。

请注意,静态 Ada 字符串与其他语言(如 C 或 Java)中的字符串非常不同。由于它们的静态特性,它们最好像我上面所做的那样内联构建,或者作为函数的返回值构建。由于函数不能返回多个值,因此单个统一的“拆分”例程显然不适合静态 Ada 字符串处理。相反,您应该按照我上面所做的那样,从 Ada.Strings.Fixed ( Headand Tail) 调用相应的例程,或者切换到 usingAda.Strings.Unbounded.Unbounded_String而不是String.

如果您想保持 Java 对字符串处理的心态,后者可能是最简单的选择。不过,如果您想真正学习 Ada,我强烈建议您学习以StringAda 方式处理 static fixed 。

于 2013-02-21T15:24:05.897 回答
3

通过查看您的代码,您确实需要大致了解String 类型,因为您从其他语言中拖入了很多关于如何使用它们的期望——这些期望不会与它们一起使用。Ada 的 String 类型并不是其更灵活的特性之一,因为它们始终是固定长度的。虽然有一些方法可以解决您所描述的情况下的限制,但简单地使用Unbounded_Strings会容易得多。

您的函数的输入字符串可以保持为字符串类型,它将根据您提供给它的字符串的长度进行调整。两个输出 Unbounded_Strings 然后在对它们中的每一个调用 To_Unbounded_String() 之后简单地设置为切片的字符串组件。

于 2013-02-20T01:37:47.397 回答
1

给定主程序的约束,所有字符串都以 EMPTY_STRING 的大小为界。没有参数的过程是正确的方法,调用者分配的参数存储(在堆栈上)

情况并非总是如此,因此值得了解另一种方式。问题是如何处理直到运行时才知道大小的数据。

一些语言只能在堆上提供运行时分配(通过“new”或“malloc”)并且只能通过指针访问数据,从而留下各种混乱的问题,包括访问数据末尾(缓冲区溢出)或释放正确存储(内存泄漏,访问释放的指针等)

Ada 也会允许这种方法,但它通常是不必要的并且强烈反对。Unbounded_String 是此方法的包装器,而 Bounded_String 避免了堆分配,您可以在其中接受字符串长度的上限。

而且,Ada 允许在堆栈上创建可变大小的数据结构。该技术只涉及创建一个新的堆栈框架并在您需要的地方声明新变量,使用“声明”。新变量可以通过函数调用进行初始化。

每个函数只能返回一个对象,但该对象的大小可以在运行时确定。因此,“Split”可以实现为 2 个函数,返回 Part1 或 Part2,或者它可以返回包含两个字符串的记录。这将是一个有两个大小判别式的记录,所以我在这里选择了更简单的选项。函数结果通常就地构建(避免复制)。

您示例中的流程需要两个嵌套的 Declare 块;如果可以首先识别“Pos”,它们可以折叠成一个......

procedure Split is

   function StringBefore( Input : String; Pos : Natural) return String is
   begin
      return Input(1 .. Pos-1);
   end StringBefore;

   function StringFrom ...

begin                                           
   Put("To split a string, enter the string: ");
   declare
      AString : String := Get_Line;
      Pos     : Natural;
   begin
      Put("Enter the split position: ");
      Get(Pos);
      declare 
         Part1 : String := StringBefore(AString, Pos);
         Part2 : String := StringFrom(AString, Pos);
      begin
         Put("The first part is ");
         Put_Line(Part1);
         Put(" and the second part is ");
         Put_Line(Part2);
      end;   -- Part1 and Part2 are now out of scope
   end;      -- AString is now out of scope
end Split;

这显然可以包装在一个循环中,每次使用不同大小的字符串,没有内存管理问题。

于 2013-02-20T12:17:27.770 回答
0

查看 Ada.Strings.Fixed 中的 Head 和 Tail 函数。

function Head (Source : in String; Count : in Natural; Pad : in Character := Space) return String;

function Tail (Source : in String; Count : in Natural; Pad : in Character := Space) return String;

于 2019-02-28T04:58:07.883 回答
0

这是一种仅使用字符串切片的方法。

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
procedure Main is
   str : String := "one,two,three,four,five,six,seven,eight";
   pattern : String := ",";
   idx, b_idx : Integer;
begin
   b_idx := 1;
   for i in 1..Ada.Strings.Fixed.Count ( Source => str, Pattern => pattern ) loop
      idx := Ada.Strings.Fixed.Index( Source => str(b_idx..str'Last), Pattern => pattern);
      Put_Line(str(b_idx..idx-1)); -- process string slice in any way
      b_idx := idx + pattern'Length;
   end loop;
   -- process last string
   Put_Line(str(b_idx..str'Last)); 
end Main;
于 2020-01-23T16:45:13.200 回答