1

I was wondering if any of you could answer a quick question for me. I am currently working with records right now and in my program I need it to understand what the line of a file that i'm importing contains. My problem lies in the fact that I don't know how to "split" the line into actual variables. For example the line is

22134.09 Kia Bernice

How do I make the program know that the first part, 22134.09 is the variable price, Kia is the variable company and Bernice is the variable model, and then sort them all into a record?

Such as

type PriceCompModel is record
price : Float range 1.0..99999.99;
company : String (1..CompNameLength);
Model : String (1..ModelNameLength);

Thanks.

edited code

    with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;

procedure Testexercise is

   type Inventory is Record

      CarPrice : Float := 0.0;
      CarType  : String (1..40);
      -- CarType will include both the model and company
   end record;

   InventoryItem  : Inventory;
   ImportedFile   : File_Type;
   FileName       : String := "Cars.txt";
   WordsFromFile  : String(1..40);
   LengthofWords  : Integer ;
   PriceofCar     : Float := 0.0;
   LoopCount      : Integer := 1;

   type Cars is array (1..12) of Inventory;

   begin

      Open(File => ImportedFile, Mode => In_File, Name => FileName);

      --for I in 1..12 loop

      while LoopCount /= 12 loop

         Get(File => ImportedFile, Item => InventoryItem.CarPrice);

         Get_Line(File => ImportedFile, Item => WordsFromFile, Last=> LengthofWords);       

         Put (Integer(InventoryItem.CarPrice),1);

         Put (WordsFromFile(1..LengthofWords));

         New_Line;

         LoopCount := LoopCount + 1;

         InventoryItem.CarType := WordsFromFile;      


      end loop;
     close(ImportedFile);



   end Testexercise;

So i tried doing this within the loop

for I in 1..12 loop
    Cars := Inventory;
   end loop;

This ended up working for me after i set

Car : Cars;

for I in 1..12 loop
Car(I) := Inventory;
end loop;
Dibs
  • 7
  • 5
  • Will the file always contain exactly 12 inventory records? If the file contains fewer than 12 records you will encounter an exception when you try to read beyond the end of the file. If the file contains more than 12 records you will fail to process the extra records. – Jim Rogers Nov 27 '16 at 06:48
  • Yes I simply did this at this particular moment just for testing purposes. I can always adjust the ranges later if I want to. – Dibs Nov 27 '16 at 07:06
  • Study about array indexing. Each element of the array is accessed through an index value into the array. In your example above the Cars array index values start at 1 and end at 12. The first Inventory value should be assigned to Cars(1). The last inventory value should be assigned to Cars(12). – Jim Rogers Nov 27 '16 at 15:38
  • Yes I did that, I believe my issue was that I didn't instance a version of cars, which is my array from 1..12, as soon as i set Car : Cars; and used Car throughout the rest of the code it worked. – Dibs Nov 27 '16 at 16:12

2 Answers2

4

You have many factors to consider when defining the record to contain your information.

It will be useful to create a named subtype of float, or a named floating point type so that the I/O routines can check the input values for the price component.

Fields of type String must be constrained to a predefined size. This means that all "company" strings must be the same size, and all "model" strings must be the same size, although model strings may be a different length than company strings. If the names of companies and/or models may vary then you should consider using either bounded strings (Ada Language Reference Manual section A.4.4) or unbounded strings (Ada Language Reference Manual section A.4.5).

If the strings of the input file are fixed in size you can use Ada.Text_IO.Text_Streams (Ada Language Reference Manual section A.12.2) to read each field of the record. If the strings can be different sizes then you will need to read and parse each field manually using Ada.Text_IO.

-- Read record data from a file
with Ada.Text_Io; use Ada.Text_IO;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Strings.Fixed; use Ada.Strings.Fixed;

procedure read_record is
   type Prices is delta 0.01  digits 7 range 0.0..99999.99;
   type Auto_Inventory is record
      Price   : Prices := 0.0;
      Company : Unbounded_String := Null_Unbounded_String;
      Model   : Unbounded_String := Null_Unbounded_String;
   end record;
   package AI_IO is new Ada.Text_IO.Decimal_IO(Prices);
   use AI_IO;

   Inventory_Item : Auto_Inventory;
   The_File  : File_Type;
   File_Name : String := "inventory.txt";
   Inpt_Str  : String(1..1024);
   Length    : Natural;
   Start, Finis : Positive;
begin
   Open(File => The_File,
        Mode => In_File,
        Name => File_Name);
   Get(File => The_File,
       Item => Inventory_Item.Price);
   Get_Line(File => The_File,
            Item => Inpt_Str,
            Last => Length);
   Close(The_File);
   Start := Index_Non_Blank(Source => Inpt_Str(1..Length));
   Finis := Start;
   while Finis < Length and then Inpt_Str(Finis) /= ' ' loop
      Finis := Finis + 1;
   end loop;
   Inventory_Item.Company := To_Unbounded_String(Inpt_Str(Start..Finis));
   Start := Index_Non_Blank(Inpt_Str(Finis + 1..Length));
   Inventory_Item.Model := To_Unbounded_String(Inpt_Str(Start..Length));
   Put_Line("Price: " & Prices'Image(Inventory_Item.Price));
   Put_Line("Company: " & To_String(Inventory_Item.Company));
   Put_Line("Model: " & To_String(Inventory_Item.Model));
end read_record;

If you want to read a file containing many records you need to collect the information in some kind of container. The following example uses a Vector from the generic package Ada.Containers.Vectors.

-- Auto Inventory Package specification
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Vectors;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;

package Auto_Inventory is
   type Prices is delta 0.01 digits 7 range 0.0..99999.99;
   type Automobile is tagged private;
   procedure Print(Item : Automobile);
   function Set return Automobile;
   function Get_Price(Item : Automobile) return Prices;
   function Get_Company(Item : Automobile) return String;
   function Get_Model(Item : Automobile) return String;

   type Inventory is tagged private;
   procedure Read(Item : out Inventory; File : File_Type) with
     Pre => Mode(File) = In_File;

   procedure Write(Item : in Inventory; File : File_type) with
     Pre => Mode(File) = Out_File;

   procedure Print(Item : Inventory);
private
   type Automobile is tagged record
      Price   : Prices := 0.0;
      Company : Unbounded_String := Null_Unbounded_String;
      Model   : Unbounded_String := Null_Unbounded_String;
   end record;

   package Auto_Vect is new 
     Ada.Containers.Vectors(Index_Type   => Positive,
                            Element_Type => Automobile);
   use Auto_Vect;
   type Inventory is tagged record
      List : Vector;
   end record;
end Auto_Inventory;

The body for this package is:

with Ada.Strings.Fixed; use Ada.Strings.Fixed;

package body Auto_Inventory is
   package Prices_IO is new Ada.Text_IO.Decimal_IO(Prices);
   use Prices_IO;
   -----------
   -- Print --
   -----------

   procedure Print (Item : Automobile) is
      use Prices_Io;
   begin
      Put_Line("Price  : " & Prices'Image(Item.Price));
      Put_Line("Company: " & To_string(Item.Company));
      Put_Line("Model  : " & To_String(Item.Model));
      New_Line;
   end Print;

   ---------
   -- Set --
   ---------

   function Set return Automobile is
      Temp     : Automobile;
      Inpt_Str : String(1..1024);
      Length   : Natural;
   begin
      Put("Enter the automobile price: ");
      Get(Item => Temp.Price);
      Put("Enter the automobile company: ");
      Get_Line(Item => Inpt_Str, Last => Length);
      Temp.Company := To_Unbounded_String(Inpt_Str(1..Length));
      Put("Enter the automobile model: ");
      Get_Line(Item => Inpt_Str, Last => Length);
      Temp.Model := To_Unbounded_String(Inpt_Str(1..Length));
      return Temp;
   end Set;

   ---------------
   -- Get_Price --
   ---------------

   function Get_Price (Item : Automobile) return Prices is
   begin
      return Item.Price;
   end Get_Price;

   -----------------
   -- Get_Company --
   -----------------

   function Get_Company (Item : Automobile) return String is
   begin
      return To_String(Item.Company);
   end Get_Company;

   ---------------
   -- Get_Model --
   ---------------

   function Get_Model (Item : Automobile) return String is
   begin
      return To_String(Item.Model);
   end Get_Model;

   ----------
   -- Read --
   ----------

   procedure Read (Item : out Inventory;
                   File : File_Type)   is
      Temp : Inventory;
      Auto : Automobile;
      Inpt_Str : String(1..1024);
      Length   : Natural;
      Start, Finis : Positive;
   begin
      while not End_Of_File(File) loop
         Get(File => File, Item => Auto.Price);
         Get_Line(File => File, Item => Inpt_str, Last => Length);
         Start := Index_Non_Blank(Inpt_Str(1..Length));
         Finis := Start;
         while Finis < Length and then Inpt_Str(Finis) /= ' ' loop
            Finis := Finis + 1;
         end loop;
         Auto.Company := To_Unbounded_String(Inpt_Str(Start..Finis - 1));
         Start := Index_Non_Blank(Inpt_Str(Finis..Length));
         Auto.Model := To_Unbounded_String(Inpt_Str(Start..Length));
         Temp.List.Append(Auto);
      end loop;
      Item := Temp;
   end Read;

   -----------
   -- Write --
   -----------

   procedure Write (Item : in Inventory;
                    File : File_type) is

   begin
      for Element of Item.List loop
         Put(File => File, Item => Prices'Image(Element.Price) &
               " " & To_String(Element.Company) & " " & 
               To_String(Element.Model));
         New_Line;
      end loop;

   end Write;

   -----------
   -- Print --
   -----------

   procedure Print (Item : Inventory) is
   begin
      for Element of Item.List loop
         Element.Print;
      end loop;
   end Print;

end Auto_Inventory;

An example of a main procedure to exercise this package:

------------------------------------------------------------------
-- Read a file of many records --
------------------------------------------------------------------
with Auto_Inventory; use Auto_Inventory;
with Ada.Text_IO; use Ada.Text_IO;

procedure read_file is
   The_Inventory : Inventory;
   The_File  : File_Type;
   File_Name : String := "inventory.txt";
begin
   Open(File => The_File,
        Mode => In_File,
        Name => File_Name);
   The_Inventory.Read(The_File);
   Close(The_File);
   The_Inventory.Print;
end read_file;

An example input file for this program is:

22134.09 Kia Bernice
12201.15 Nissan Versa
22349.99 Chevrolet Cruse
Jim Rogers
  • 4,822
  • 1
  • 11
  • 24
  • I see and if I need to read multiple lines of info and then access them later then could i simply loop the entire thing and have a counter that increases by one at the end of each iteration? I've just begun delving into code and I'm pretty much a novice when it comes to file input, output, and reading. Thanks a lot! – Dibs Nov 26 '16 at 06:12
  • You might choose an array of records to store the inputs, or you could store them in a vector or a linked list. The use of an array is simple, but you need to allocate at least enough elements in the array before you start reading in the elements. Vectors and linked lists can be grown as needed during the process of reading the records from the file. Generic vectors and linked lists are available in the Ada.Containers packages. See the Ada Language Reference Manual sections A.18.11 and A.18.12. – Jim Rogers Nov 26 '16 at 08:49
  • I edited my answer to show an example of handling a multi-line file. – Jim Rogers Nov 26 '16 at 16:06
  • What do you think about this for some code. I'm now trying to save my created record into an array of records, and then later sort the records from price lowest to highest. I'm struggling a bit with saving the record into the array of records which then can be accessed and reorganized. – Dibs Nov 27 '16 at 02:06
-3

It is not clear for me what language you are using .However the concept is to deal with each line from the file alone then process it with a function that do the token-zing or splitting depending on the language you use and save each token in a variable depending on how the function you are using will save the tokens

for example:

In java there is a class

StringTokenizer(String str, String delim)

     StringTokenizer st = new StringTokenizer("this is a test", "$a; ");
 while (st.hasMoreTokens()) {
     System.out.println(st.nextToken());
 }

delim in your case is space so use the format

StringTokenizer st = new StringTokenizer("this is a test");

or

    String line = reader.readLine();

  String[] tokens = line.split("\\s"); 

note that you need to save the line you read in a string so you can use those functions in java then access each token from the array

 String price =  tokens[1]  and so on 

for other languages please find the following resources:

In c https://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm

In pyhton https://www.tutorialspoint.com/python/string_split.htm

learn
  • 16
  • 1