To lower case recursive algorithm - recursion

I have this code for returning a string in all lower case, using recursion:
function min(ch:string):string;
begin
if ( ch = '' ) then
min:= ''
else
if (ch[1] in ['A'..'Z']) then
begin
ch[1]:=chr(ord(ch[1])+32);
min:= ch[1] + min(copy(ch,2,length(ch)-1));
end;
end;
But it doesn't work:
When I run it with the example min('AbC') the output is a only not abc.
Where is the problem here?

The problem is that you do not always call the recursive function. As soon as you find a letter that is already lower case, you don't look any more at the characters that follow it. And so the return value is truncated up to that character.
You should also call it when the character being looked at is not a capital letter. So move the recursive call out of that if, and it will work:
function min(ch:string):string;
begin
if ( ch = '' ) then
min:= ''
else
begin
if (ch[1] in ['A'..'Z']) then
ch[1]:=chr(ord(ch[1])+32);
min:= ch[1] + min(copy(ch,2,length(ch)-1));
end;
end;
See it run on ideone.com.

Related

Function and procedure subprogram

I need to only use one function and one procedure and unfortunately I didn't manage to solve this problem.
The problem goes as following:
Create a subprogram that has three parameters. One string and two sign.
The subroutine must pick the first and last character in the string. The main program will then print these two characters.
Create a subprogram that retrieves a character, from the keyboard, which represents a truth value (see driving example).
The subprogram must send back the corresponding truth value to the main program.
In the terminal it should look like:
Type a string containing 6 characters: Overfl
First character is: O
Last character is : l
Type F or T (for False or True): T
You typed True
This is how my code looks like:
with Ada.Text_IO; use Ada.Text_IO;
procedure Test is
procedure String_Check(
S : in String;
Char_1, Char_2 : out Character
) is
begin
Char_1 := S(S'First);
Char_2 := S(S'Last);
end String_Check;
function Character_Check return Boolean is
Check : Integer;
begin
Put("Type F or T (For False or True): ");
Get(Check)
if Check = 'T' then
return True;
else
return False;
end if;
end Character_Check;
Char_1, Char_2 : Character;
Check : Character;
S : String(1 .. 6);
begin
Put("Type a string containing 6 characters: ");
Get(S);
String_Check(S, Char_1, Char_2);
Put("First character is: ");
Put(Char_1);
New_Line;
Put("Last character is: ");
Put(Char_2);
Skip_Line;
New_Line(2);
Put("You typed ");
if Character_Check then
Put("True");
else
Put("False");
end if;
end Test;
My code runs but it doesn't fulfill the given requirements. I guess I can't use a function in my second subprogram because the instruction says "create a subprogram that receives a character from the keyboard". How am I supposed to do Get in a function? But if I make my second program to a procedure I have to make my first program to a function. How am I supposed to do return for two values at the same time?

Creating plsql function for Factorial program

When I call the function using select statement
[select fact(5) from dual;]
I get output as 1.Can you guys please help me from the below code
create or replace function fact(num in number)
return number
Is
res_fact number:=1;
begin
for i in 1..5 loop
res_fact:=res_fact*i;
dbms_output.put_line(res_fact);
-- dbms_output.put_line('Factorial of '||num||' = '||res_fact);
return res_fact;
end loop;
dbms_output.put_line(res_fact);
end;
res_fact=res_fact*i;
as i call function i used to get the factorial of that input number
res_fact=5*4*3*2*1;
res_fact=120
Make this code "return res_fact;" out of loop you code will run, But above code work for only 5.
Two issues....
Firstly you need to move your return statement outside of your loop. As you now have it it will return on the first pass through the loop.
Secondly you are ignoring your input parameter and always going to get factorial of 5 rather than what is passed in (once you move your return statement.
See code below
create or replace function fact(num in number)
return number
Is
res_fact number:=1;
begin
for i in 1..num loop
res_fact:=res_fact*i;
end loop;
dbms_output.put_line('Factorial of '||num||' = '||res_fact);
return res_fact;
end;

PL/SQL annoymous procedure + cursor problems

I am trying to write an anonymous block as follows, but it always give me error messages as
Encountered the symbol "=" when expecting one of the following. ( ) , * # % & - + / at mod remainder rem and or || multiset.
I don't know what it means.
You're missing a : in front of the =in several places, e.g. here:
get_sectno='1031';
The assignment operator in PL/SQL is :=- = is (just like in plain SQL) comparison for equality.
You're also missing the ; at the end of every call to
lowest_average (get_term, get_sectno, get_ctitle, get_sid, get_sname, get_average)

Ada 95 Check if enter was pressed

I am new to Ada.
How can I check if enter was pressed?
The while loop should be able to check whether the input character is a white space or an enter key.
Furthermore, how can I check the user input type, like the type() or typeof() function in other languages?
FUNCTION ReadValue RETURN Unbounded_String IS
ValueChar : Character;
Result : Unbounded_String := To_Unbounded_String("NULL");
BEGIN
Get(ValueChar);
Skip_Line;
WHILE ValueChar /= ';'LOOP
Get(ValueChar);
IF IsValidNameInput(ValueChar) THEN
Result := Result & ValueChar;
ELSE
exit;
END IF;
END LOOP;
ValueIntegerFlag := CheckValue(Value);
RETURN Result;
END ReadValue;
Read the characters one-at-a-time without special ENTER handling using Get_Immediate instead of Get - ARM A.10.7(9).
You can do checks on the class of the character you’ve just read using Ada.Characters.Handling - ARM A.3.2 - something like
function Is_Valid_Name_Input (Ch : Character) return Boolean is
begin
return Ada.Characters.Handling.Is_Graphic (Ch)
and then not Ada.Characters.Handling.Is_Space (Ch);
end Is_Valid_Name_Input;
(probably not quite what you want, since it makes &*^$$^ a valid name!)
Ada.Characters.Handling.Is_Line_Terminator detects ENTER (on Unix; probably on Windows too).
You can check whether a string corresponds to an integer by trying the conversion and catching the exception when it fails:
function Check_Integer_Value (Str : Unbounded_String) return Boolean is
Dummy : Integer;
begin
Dummy := Integer'Value (To_String (Str));
return True;
exception
when Constraint_Error =>
return False;
end Check_Integer_Value;
With regard to ReadValue:
Don’t initialize Result - it starts off as the empty string (and you really don’t want to start with the string ”NULL”).
It skips the first character input.
What’s that Skip_Line for?
Try something like
function Read_Value return Unbounded_String is
Value_Char : Character;
Result : Unbounded_String;
begin
loop
Get_Immediate (Value_Char);
exit when Value_Char = ';';
if Is_Valid_Name_Input (Value_Char) then
Result := Result & Value_Char;
end if;
end loop;
return Result;
end Read_Value;

Ada String Concatenation

I have a function that returns a string for a particular item, and I need to call that function numerous times and combine those strings into one. The combined string is bounded. I've made sure to fill it when space characters when it initializes but I keep getting "length check failed" errors. Is there something basic I'm doing wrong here?
FOR I IN 1..Collection.Size LOOP
Combined_String := combined_string & Tostring(Collection.Book(I));
END LOOP;
Unbounded_String is probably the easiest way to go:
with Ada.Strings.Unbounded;
use Ada.Strings.unbounded;
...
Temp_Unbounded_String : Unbounded_String; -- Is empty by default.
...
for I in 1 .. Collection.Size loop
Append(Temp_Unbounded_String, ToString(Collection.Book(I));
end loop;
If you then need to have the result placed in your fixed length standard string:
declare
Temp_String : constant String := To_String(Temp_Unbounded_String);
begin
-- Beware! If the length of the Temp_String is greater than that of the
-- fixed-length string, a Constraint_Error will be raised. Some verification
-- of source and target string lengths must be performed!
Combined_String(Temp_String'Range) := Temp_String;
end;
Alternatively, you can use the Ada.Strings.Fixed Move() procedure to bring the Unbounded_String into the target fixed-length string:
Ada.Strings.Fixed.Move(To_String(Temp_Unbounded_String), Combined_String);
In this case, if the source string is "too long", by default a Length_Error exception is raised. There are other parameters to Move() that can modify the behavior in that situation, see the provided link on Move for more detail.
In order to assign Combined_String, you must assign the full correct length at once. You can't "build up" a string and assign it that way in Ada.
Without seeing the rest of your code, I think Ada.Strings.Unbounded is probably what you should be using.
I know this is an ancient question, but now that Ada 2012 is out I thought I'd share an idiom I've been finding myself using...
declare
function Concatenate(i: Collection'index)
is
(tostring(Collection(i) &
if (i = Collection'last) then
("")
else
(Concatenate(i+1))
);
s: string := Concatenate(Collection'first);
begin
Put_Line(s);
end;
Typed off the top of my head, so it'll be full of typos; and if you want it to work on empty collections you'll need to tweak the logic (should be obvious).
Ada 2012's expression functions are awesome!
Ada works best when you can use perfectly-sized arrays and strings. This works wonderfully for 99% of string uses, but causes problems any time you need to progressively build a string from something else.
Given that, I'd really like to know why you need that combined string.
If you really need it like that, there are two good ways I know of to do it. The first is to use "unbounded" (dynamically-sized) strings from Ada.Strings.Unbounded, as Dave and Marc C suggested.
The other is to use a bit of functional programming (in this case, recursion) to create your fixed string. Eg:
function Combined_String (String_Collection : in String_Collection_Type) return String is
begin
if String_Collection'length = 1 then
return String_Collection(String_Collection'first);
end if;
return String_Collection(String_Collection'first) &
Combined_String (String_Collection'first + 1 .. String_Collection'last);
end Combined_String;
I don't know what type you used for Collection, so I'm making some guesses. In particular, I'm assuming its an unconstrained array of fixed strings. If it's not, you will need to replace some of the above code with whatever your container uses to return its bounds, access elements, and perform slicing.
From AdaPower.com:
function Next_Line(File : in Ada.Text_IO.File_Type :=
Ada.Text_Io.Standard_Input) return String is
Answer : String(1..256);
Last : Natural;
begin
Ada.Text_IO.Get_Line(File => File,
Item => Answer,
Last => Last);
if Last = Answer'Last then
return Answer & Next_Line(File);
else
return Answer(1..Last);
end if;
end Next_Line;
As you can see, this method builds a string (using Get_Line) of unlimited* length from the file it's reading from. So what you'll need to do, in order to keep what you have is something on the order of:
function Combined_String (String_Collection : in String_Collection_Type)
Return String is
begin
if String_Collection'length = 1 then
Return String_Collection(String_Collection'First).All;
end if;
Recursion:
Declare
Data : String:= String_Collection(String_Collection'First).All;
SubType Constraint is Positive Range
Positive'Succ(String_Collection'First)..String_Collection'Last;
Begin
Return Data & Combined_String( String_Collection(Constraint'Range) );
End Recursion;
end Combined_String;
Assuming that String_Collection is defined as:
Type String_Collection is Array (Positive Range <>) of Access String;
*Actually limited by Integer'Range, IIRC

Resources