动态字符串包
Example program ------> e_c16_p3.ada
-- Chapter 16 - Program 3
-- This is a dynamic string package which can be used as an aid
-- in writing string intensive programs. Ada only has a static
-- string capability, so this package was written as an example of
-- how the Ada programming language can be expanded. The basis
-- for this package is the dynamic string available with the
-- Borland International implementation of Pascal, TURBO Pascal.
-- A dynamic string is defined as an array of characters of maximum
-- length of 255. The dynamic length of the dynamic string is
-- stored in the string location with index = 0, so the dynamic
-- string must be defined with a lower limit of 0 and an upper
-- limit of whatever the desired maximum length of the string is
-- to be. The subtype STRING_SIZE below limits the string length
-- when it is defined.
-- Put Outputs a dynamic string to the monitor
-- ConCat Concatenates two dynamic strings and puts the result
-- into a third dynamic string
-- Copy Copies a dynamic string to another dynamic string
-- Copy Copies a static string to a dynamic string
-- Delete Deletes a group of characters from a dynamic string
-- Insert Inserts a group of characters into a dynamic string
-- Length Returns the dynamic length of a dynamic string
-- Size_Of Returns the static length of a dynamic string
-- Pos Returns the first location of a dynamic string within
-- another dynamic string
with Ada.Text_IO; use Ada.Text_IO;
package DynStrng is
subtype STRING_SIZE is INTEGER range 0..255;
type DYNAMIC_STRING is array(STRING_SIZE range <>) of CHARACTER;
-- Put : Display a dynamic string on the monitor.
procedure Put(Input_String : in DYNAMIC_STRING);
-- ConCat : Concatenation - The First_String is copied into the
-- Result_String, then the Second_String is copied
-- into the Result_String following the First_String.
-- If all characters fit, Result is set to TRUE.
-- If Result_String will not hold all characters,
-- only as many as will fit are copied and Result
-- is set to FALSE.
-- Result = TRUE, complete copy done.
-- Result = FALSE, some or all not copied
procedure ConCat(First_String : in DYNAMIC_STRING;
Second_String : in DYNAMIC_STRING;
Result_String : in out DYNAMIC_STRING;
Result : out BOOLEAN);
-- Copy : The String contained in Input_String is copied into
-- the string Output_String. This procedure is
-- overloaded to include copying from either dynamic
-- strings or static strings.
-- Result = TRUE, complete copy done
-- Result = FALSE, some or all not copied
procedure Copy(Input_String : in DYNAMIC_STRING;
Output_String : in out DYNAMIC_STRING;
Result : out BOOLEAN);
procedure Copy(Input_String : in STRING;
Output_String : out DYNAMIC_STRING;
Result : out BOOLEAN);
-- Delete : Beginning at First_Position, as many characters as are
-- indicated by Number_Of_Characters are deleted from
-- String_To_Modify. If there are not that many, only
-- as many as are left are deleted.
-- Result = TRUE, deletion was complete
-- Result = FALSE, only a partial deletion was done
procedure Delete(String_To_Modify : in out DYNAMIC_STRING;
First_Position : in STRING_SIZE;
Number_Of_Characters : in STRING_SIZE;
Result : out BOOLEAN);
-- Insert : The string String_To_Insert is inserted into the string
-- String_To_Modify begining at location Place_To_Insert
-- if there is enough room.
-- Result = TRUE, insert completed in full
-- Result = FALSE, not enough room for full insert
procedure Insert(String_To_Modify : in out DYNAMIC_STRING;
String_To_Insert : in DYNAMIC_STRING;
Place_To_Insert : in STRING_SIZE;
Result : out BOOLEAN);
-- Length : Returns the dynamic length of the string defined by
-- String_To_Measure.
function Length(String_To_Measure : in DYNAMIC_STRING)
return STRING_SIZE;
-- Size_Of : Returns the static length of the string, the actual
-- upper limit of the string definition.
function Size_Of(String_To_Measure : in DYNAMIC_STRING)
return STRING_SIZE;
-- Pos : Position of substring - The string String_To_Search is
-- searched for the string Required_String beginning
-- at Place_To_Start.
-- Result = TRUE, a search was possible
-- Result = FALSE, no search could be made
-- Location_Found = 0, no string found
-- Location_Found = N, start of matching string
procedure Pos(String_To_Search : in DYNAMIC_STRING;
Required_String : in DYNAMIC_STRING;
Place_To_Start : in STRING_SIZE;
Location_Found : out STRING_SIZE;
Result : out BOOLEAN);
end DynStrng;
package body DynStrng is
-- The display procedure overloads the existing
-- Put procedures to output a dynamic string. Note
-- that the existing Put is used in this new Put.
procedure Put(Input_String : in DYNAMIC_STRING) is
begin
for Index in 1..CHARACTER‘POS(Input_String(0)) loop
Put(Input_String(Index));
end loop;
end Put;
procedure ConCat(First_String : in DYNAMIC_STRING;
Second_String : in DYNAMIC_STRING;
Result_String : in out DYNAMIC_STRING;
Result : out BOOLEAN) is
Intermediate_Result : BOOLEAN;
Character_Count : STRING_SIZE;
Room_Left : STRING_SIZE;
begin
-- Copy the first into the result string
Copy(First_String,Result_String,Intermediate_Result);
if Intermediate_Result then
Character_Count := CHARACTER‘POS(Second_String(0));
Room_Left := Result_String‘LAST
- CHARACTER‘POS(Result_String(0));
Result := TRUE;
if Character_Count > Room_Left then
Character_Count := Room_Left;
Result := FALSE;
end if;
for Index in 1..Character_Count loop
Result_String(Index + CHARACTER‘POS(Result_String(0))) :=
Second_String(Index);
end loop;
Result_String(0) :=
CHARACTER‘VAL(CHARACTER‘POS(Result_String(0))
+ Character_Count);
else
Result := FALSE;
end if;
end ConCat;
-- This procedure overloads the name Copy to
-- copy from one dynamic string to another.
procedure Copy(Input_String : in DYNAMIC_STRING;
Output_String : in out DYNAMIC_STRING;
Result : out BOOLEAN) is
Character_Count : STRING_SIZE;
begin
-- First pick the smallest string size
Character_Count := CHARACTER‘POS(Input_String(0));
if Character_Count > Output_String‘LAST then
Character_Count := Output_String‘LAST;
Result := FALSE; -- The entire string didn‘t fit
else
Result := TRUE; -- The entire string fit
end if;
for Index in 0..Character_Count loop
Output_String(Index) := Input_String(Index);
end loop;
Output_String(0) := CHARACTER‘VAL(Character_Count);
end Copy;
-- This routine overloads the copy procedure name
-- to copy a static string into a dynamic string.
procedure Copy(Input_String : in STRING;
Output_String : out DYNAMIC_STRING;
Result : out BOOLEAN) is
Character_Count : STRING_SIZE;
begin
-- First pick the smallest string size
Character_Count := Input_String‘LAST;
if Character_Count > Output_String‘LAST then
Character_Count := Output_String‘LAST;
Result := FALSE; -- The entire string didn‘t fit
else
Result := TRUE; -- The entire string fit
end if;
for Index in 1..Character_Count loop
Output_String(Index) := Input_String(Index);
end loop;
Output_String(0) := CHARACTER‘VAL(Character_Count);
end Copy;
procedure Delete(String_To_Modify : in out DYNAMIC_STRING;
First_Position : in STRING_SIZE;
Number_Of_Characters : in STRING_SIZE;
Result : out BOOLEAN) is
Number_To_Delete : STRING_SIZE;
Number_To_Move : STRING_SIZE;
Last_Dynamic_Character : STRING_SIZE :=
CHARACTER‘POS(String_To_Modify(0));
begin
-- can we delete any at all?
if First_Position > Last_Dynamic_Character then
Result := FALSE;
return;
end if;
-- Decide how many to delete
if (First_Position + Number_Of_Characters)
> Last_Dynamic_Character then
Number_To_Delete := Last_Dynamic_Character
- First_Position + 1;
Result := FALSE;
else
Number_To_Delete := Number_Of_Characters;
Result := TRUE;
end if;
-- find out how many to move back
if (Last_Dynamic_Character - (First_Position + Number_To_Delete))
>= 0 then
Number_To_Move := 1 + Last_Dynamic_Character
- (First_Position + Number_To_Delete);
else
Number_To_Move := 0;
end if;
-- now delete the characters by moving them back
for Index in First_Position..
(First_Position + Number_To_Move - 1) loop
String_To_Modify(Index) := String_To_Modify(Index
+ Number_To_Delete);
end loop;
String_To_Modify(0) :=
CHARACTER‘VAL(CHARACTER‘POS(String_To_Modify(0))
- Number_To_Delete);
end Delete;
procedure Insert(String_To_Modify : in out DYNAMIC_STRING;
String_To_Insert : in DYNAMIC_STRING;
Place_To_Insert : in STRING_SIZE;
Result : out BOOLEAN) is
Number_To_Add : STRING_SIZE;
Number_To_Move : STRING_SIZE;
Room_Left : STRING_SIZE;
begin
-- Can we add any at all?
if (Place_To_Insert > String_To_Modify‘LAST) or
(Place_To_Insert > CHARACTER‘POS(String_To_Modify(0)) + 1) then
Result := FALSE;
return;
end if;
Result := TRUE;
-- How many can we add?
Number_To_Add := String_To_Modify‘LAST - Place_To_Insert + 1;
if Number_To_Add > CHARACTER‘POS(String_To_Insert(0)) then
Number_To_Add := CHARACTER‘POS(String_To_Insert(0));
end if;
-- Find how many to move forward
Number_To_Move := CHARACTER‘POS(String_To_Modify(0))
- Place_To_Insert + 1;
Room_Left := String_To_Modify‘LAST - Place_To_Insert + 1;
if Room_Left < Number_To_Move then
Number_To_Move := Room_Left;
end if;
-- Move them forward
for Index in reverse Place_To_Insert..Place_To_Insert
+ Number_To_Move - 1 loop
String_To_Modify(Index + Number_To_Add) :=
String_To_Modify(Index);
end loop;
for Index in 1..Number_To_Add loop
String_To_Modify(Index + Place_To_Insert - 1) :=
String_To_Insert(Index);
end loop;
-- Increase the length of the string
String_To_Modify(0) := CHARACTER‘VAL(
CHARACTER‘POS(String_To_Modify(0)) + Number_To_Add);
if CHARACTER‘POS(String_To_Modify(0)) > String_To_Modify‘LAST
then
String_To_Modify(0) := CHARACTER‘VAL(String_To_Modify‘LAST);
end if;
end Insert;
-- This returns the dynamic length of a string
function Length(String_To_Measure : in DYNAMIC_STRING)
return STRING_SIZE is
begin
return CHARACTER‘POS(String_To_Measure(0));
end Length;
-- This returns the static length of a string
function Size_Of(String_To_Measure : in DYNAMIC_STRING)
return STRING_SIZE is
begin
return String_To_Measure‘LAST;
end Size_Of;
procedure Pos(String_To_Search : in DYNAMIC_STRING;
Required_String : in DYNAMIC_STRING;
Place_To_Start : in STRING_SIZE;
Location_Found : out STRING_SIZE;
Result : out BOOLEAN) is
End_Search : STRING_SIZE;
Characters_All_Compare : BOOLEAN;
begin
Location_Found := 0;
-- can we search the string at all?
if (Place_To_Start < CHARACTER‘POS(String_To_Search(0))) and
(Place_To_Start < String_To_Search‘LAST) then
Result := TRUE;
else
Result := FALSE;
return;
end if;
-- search the loop for the string now
End_Search := CHARACTER‘POS(String_To_Search(0)) -
CHARACTER‘POS(Required_String(0)) + 1;
for Index in Place_To_Start..End_Search loop -- search loop
Characters_All_Compare := TRUE;
for Count in 1..CHARACTER‘POS(Required_String(0)) loop
if Required_String(Count) /=
String_To_Search(Count + Index - 1) then
Characters_All_Compare := FALSE;
exit; -- exit loop, a character did not match
end if;
end loop;
if Characters_All_Compare then
Location_Found := Index;
return; -- string match found, return location
end if;
end loop; -- end search loop
end Pos;
end DynStrng;
下一个示例程序名为e_c16_p3.ada,它实现了我们在研究字符串时所做的承诺。当时,我们提到ada83没有动态字符串功能,但是ada95有几个包,这些包在ARM中定义为Ada环境的一部分。学习如何在生产程序中使用这些提供的包对您是有利的。就目前而言,花点时间研究e_c16_p3.ada 中包含的动态字符串包将是有益的,因为它说明了如何使用我们在本教程中研究的许多构造
动态字符串包虽然实现了动态字符串包的完整版本,但并不是作为字符串包中的最后一个字提交的。事实上,它有一个问题,我们将在本章后面描述。即使我们解决了这个问题,还有一个更好的字符串包,我们可以在所有的生产程序中使用。这一点也将在本章后面讨论。
我们在本教程中还没有研究过一个结构,尽管我们在上一章中顺便提到过它。第33行包含一个无约束数组类型声明。在名为e_c16_p4.ada的程序的第9行和第10行中说明了它的用法。本教程的第2部分将研究无约束数组。除了这个构造,e_c16_p3.ada没有使用我们在本教程中尚未研究过的ada部分,因此它没有利用ada的高级构造。它只是一个教学辅助工具,但您可以在制作程序中使用它,欢迎您作为Coronado Enterprises教程的用户使用它。您有权将所包含的任何软件用于您认为必要的任何目的,但教程本身的商业化除外。您可能需要为自己的目的稍微修改一个程序,并且您有权这样做。
这里定义的动态字符串最大长度为255个字符,动态长度存储在下标为零的字符串的第一个元素中。因此,必须将字符串声明为下界为0的字符串,上界表示该字符串将被要求存储的最大长度。这个定义来自于borlandinternational对Pascal的实现,他们将其称为turbopascal。
DYNSTRNG规范
DynStrng的规范包在该文件的第29行到第116行中进行了定义,该文件有很好的注释,给出了该包的完整定义,并描述了如何使用它。正文在第124行到第384行中给出,并给出了实际的实现。请注意,有些软件开发人员只提供包的规范部分,而这正是您真正需要使用它的部分,并对您隐藏正文。如果它们提供了编译后的主体和规范源代码,那么您就可以将包与特定编译器一起使用。你的编译器附带了这个包Ada.Text_IO文件,一个标准包,而您的编译器作者几乎肯定没有向您提供源代码的正文。这个Ada.Text_IO文件如ARM中所定义的,包只是包的规范部分Ada.Text_IO文件. 可在ARM的附录A.10.1中找到。
您应该注意这样一个事实:我们正在重载这个包的第36行上的名称,这样我们就可以使用它向监视器输出一个动态字符串。系统根据实际使用的参数类型知道我们希望使用哪一个。细心的观察者会注意到我们使用Ada.Text_IO文件版本的Put在第132行的程序中用来重载名称Put。继续讨论重载,您将看到我们在第60行和第63行中定义了两个同名的过程,再次根据类型为每个调用选择适当的过程。
研究DynStrng包,直到你觉得你能很好地理解它,然后编译这个文件为下一个程序做准备。
---------------------------------------------------------------------------------------------------------------------------
原英文版出处:https://perso.telecom-paristech.fr/pautet/Ada95/a95list.htm
翻译(百度):博客园 一个默默的 *** 的人
原文:https://www.cnblogs.com/yangjianfengzj/p/14634910.html