ada split() method

孤街浪徒 提交于 2019-12-10 22:22:43

问题


I am trying to write an Ada equivalent to the split() method in Java or C++. I am to intake a string and an integer and output two seperate string values. For example: split of "hello" and 2 would return: "The first part is he and the second part is llo"

The code I have is as follows:

-- 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;

The main part I am having trouble with is returning the two separate string values and in general the whole split() function. Any pointers or help is appreciated. Thank you


回答1:


Instead of a function, consider making Split a procedure having two out parameters, as you've shown. Then decide if Pos is the last index of Part1 or the first index of Part2; I've chosen the latter.

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;

Note that String indexes are Positive:

type String is array(Positive range <>) of Character;
subtype Positive is Integer range 1 .. Integer'Last;



回答2:


Doing this is so trivial, I'm not sure why you'd bother making a routine for it. Just about any routine you could come up with is going to be much harder to use anyway.

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

Done.

Note that static Ada strings are very different than strings in other languages like C or Java. Due to their static nature, they are best built either inline like I've done above, or as return values from functions. Since functions cannot return more than one value, a single unified "split" routine is just plain not a good fit for static Ada string handling. Instead, you should either do what I did above, call the corresponding routines from Ada.Strings.Fixed (Head and Tail), or switch to using Ada.Strings.Unbounded.Unbounded_String instead of String.

The latter is probably the easiest option, if you want to keep your Java mindset about string handling. If you want to really learn Ada though, I'd highly suggest you learn to deal with static fixed Strings the Ada way.




回答3:


From looking over your code you really need to read up in general on the String type, because you're dragging in a lot of expectations in from other languages on how to work with them--which aren't going to work with them. Ada's String type is not one of its more flexible features, in that they are always fixed length. While there are ways of working around the limitations in a situation such as you're describing, it would be much easier to simply use Unbounded_Strings.

The input String to your function could remain of type String, which will adjust to the length of the string that you provide to it. The two output Unbounded_Strings then are simply set to the sliced string components after invoking To_Unbounded_String() on each of them.




回答4:


Given the constraints of your main program, with all strings bounded by the size of EMPTY_STRING. the procedure with out parameters is the correct approach, with the out parameter storage allocated by the caller (on the stack as it happens)

That is not always the case, so it is worth knowing another way. The problem is how to deal with data whose size is unknown until runtime.

Some languages can only offer runtime allocation on the heap (via "new" or "malloc") and can only access the data via pointers, leaving a variety of messy problems including accesses off the end of the data (buffer overruns) or releasing the storage correctly (memory leaks, accessing freed pointers etc)

Ada will allow this method too, but it is usually unnecessary and strongly discouraged. Unbounded_String is a wrapper over this method, while Bounded_String avoids heap allocation where you can accept an upper bound on the string length.

But also, Ada allows variable sized data structures to be created on the stack; the technique just involves creating a new stack frame and declaring new variables where you need to, with "declare". The new variables can be initialised with function calls.

Each function can only return one object, but that object's size can be determined at runtime. So either "Split" can be implemented as 2 functions, returning Part1 or Part2, or it can return a record containing both strings. It would be a record with two size discriminants, so I have chosen the simpler option here. The function results are usually built in place (avoids copying).

The flow in your example would require two nested Declare blocks; if "Pos" could be identified first, they could be collapsed into one...

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;

This can obviously be wrapped in a loop, with different size strings each time, with no memory management issues.




回答5:


Look at the Head and Tail functions in Ada.Strings.Fixed.

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;



来源:https://stackoverflow.com/questions/14970642/ada-split-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!