Separating numbers in a string. Pascal - pascal

I have a problem. I'm learning Pascal for only a couple of weeks and I don't know much. I have to write a program that has to calculate something out of 3 entered numbers. The problem is all 3 of them need to be entered in one edit with spaces in between. So basically I have a string 'number number number'. How do I separate these numbers as 3 separate strings so I can convert them into Integer.

In pascal there are built-in procedures to retrieve the input from the console.
The easiest way to get numeric inputs is to use Read()/ReadLn(), which also can make the conversion from string to a numeric value:
procedure GetNumbers(var x,y,z: Integer);
begin
WriteLn('Enter three numbers separated with space and then press enter.');
ReadLn(x,y,z);
end;
Here, the ReadLn() detects three inputs separated with a space, waits for the [Enter] key and assigns the integer values to the x,y,z variables.

Using the copy function is one way. Sorry about the formatting, I can't understand how to paste code snippets properly in these answer sections.
function TMyForm.Add( anEdit : TEdit ) : integer;
var
Idx : integer;
TempString : string;
function GetNext : integer;
begin
result := result + StrToInt( copy( TempString, 1, Idx - 1 ) );
TempString := copy( TempString, Idx + 1, MAXINT );
end;
begin
result := 0;
TempString := anEdit.Text;
repeat
Idx := pos( ' ', TempString );
if Idx > 0 then
result := GetNext;
until Idx = 0;
if trim( TempString ) <> '' then
//this is the last piece of it then
result := result + StrToInt( trim( TempString ) );
end;
You need to also take care that the values entered are numbers and not letters, usually done with try..except blocks.

Related

Stuck on a loop while trying to verify characters from a text file

I have to make a program that reads some "random" strings of letters and numbers from a text file and checking if they meet some conditions that makes them a valid password.
The conditions are: -Have exactly 4 digits
-Have exactly 8 characters
-Have at least one uppercase letter and at least one lowercase letter
The program reads the file and it outputs the number of valid passwords.
This is the format of the text file:
"eR68G12a 91jY643ebjp eRty74kLh 24fG92 aj85gt32 dGb9357jKoup2 " (on a single line)
The code:
ยดยดยด
Program Ej23_version3;
var
char1,char2:char;
mayus,minus:boolean; // mayus and minus would be uppercase and lowercase respectively
cantDigitos,cantCaracteres,contrasenasValidas:integer;
datos:text;
Begin
assign(datos,'Datos_guia3_ej23.txt'); reset(datos);
contrasenasValidas := 0;
char1 := ' ';
Read(datos,char2);
while not eof(datos) do
Begin
mayus := false; minus := false; cantDigitos := 0; cantCaracteres := 0;
if (char1 = ' ') and (char2 <> ' ') then //check if its the beggining of the word
Begin
while not eof(datos) and (char2 <> ' ') do
Begin
cantCaracteres := cantCaracteres + 1;
if char2 = UPCASE(char2) then // if the character2 is equal to the uppercase version of the character2, character2 is uppercase
mayus := true
else
if (char2 in ['0'..'9']) then
cantDigitos := cantDigitos + 1
else
minus := true;
if eof(datos) then // when it reaches the end of the file, it also reads and checks the last character
if char2 = UPCASE(char2) then
mayus := true
else
if (char2 in ['0'..'9']) then
cantDigitos := cantDigitos + 1
else
minus := true;
End;
if minus and mayus and (cantDigitos = 4) and (cantCaracteres = 8) then //if all conditions are met, the password is valid and its added to the counter
contrasenasValidas := contrasenasValidas + 1;
char1 := char2; Read(datos, char2); //char2 should be an empty character by this point, so it passes that value to char1 and reads the next character
End
End;
WriteLn(contrasenasValidas);
End.
But when i run it, it just gets stuck there with only the prompt ticking
The problem is in the way you read the file (character by character).
It would be better to read it all at once, and examine all the sequences of eight characters one by one.
uses
SysUtils;
var
LFile: TextFile;
LStr, LSubStr: string;
LStartIndex: integer;
LExit: boolean;
begin
AssignFile(LFile, 'Datos_guia3_ej23.txt');
Reset(LFile);
ReadLn(LFile, LStr); // Get the whole line
LStartIndex := 1; // Search all 8 characters sequences, starting from the first character
LExit := FALSE;
repeat
LSubStr := Copy(LStr, LStartIndex, 8);
if Length(LSubStr) = 8 then
begin
// Here check other conditions
// ...
Inc(LStartIndex);
end else
LExit := TRUE;
until LExit;
CloseFile(LFile);
end.

get multiple inputs instead of one

So, I'm new here and I'm new to programming generally. I made this program that I needed for a project (a pascal program using Lazarus) that allows me to get a kind of list generated by replacing * by numbers. What I need is to be able to give it multiple codes to process at once (maximum 10) instead of entering every code at once.
program b;
{$mode objfpc}
{$H+}
uses sysutils;
var
sourcestr: string;
resultstr: string;
n: integer;
begin
writeln('provide a string:');
readln(sourcestr);
for n := 0 to 99 do begin
resultstr := StringReplace(sourcestr, '*', IntToStr(n div 10), []);
resultstr := StringReplace(resultstr, '*', IntToStr(n mod 10), []);
resultStr := resultStr + ':password';
writeln(resultstr);
end;
end.
I hope you could help me with this and thanks in advance.
The code below shows how to replace an arbitrary number of pairs of asterisks by the two substitute characters you are generating.
for n := 0 to 9 do begin
resultstr := sourcestr;
while Pos('*', resultstr) > 0 do begin
stringReplace(resultstr, '*', IntToStr(n div 10), []);
resultstr := StringReplace(resultstr, '*', IntToStr(n mod 10), []);
end;
resultStr := resultStr + ':password';
writeln(resultstr);
end;
It uses the Pos function in a while loop to replace the asterisk pairs. Be aware that the output may not be exactly what you need, because in each generated resultstr you will get the same substitute characters replacing each pair of asterisks, i.e.
with an input of
a ** b ** c
the resultstrs generated will be like
a00b00c
a11b11c
which may not be what you need. If not, changing the code to do what you do need is left as an exercise for the reader, as they say.
Btw, it occurred to me later that maybe you are asking how to input and process several lines'-worth of user input. One way to do that would be to read the lines into a TStringList (see online help) and then process that. Something like:
var
TL : TStringList;
sourcestr : String;
begin
TL := TStringList.Create;
repeat
readln(sourcestr);
if sourcestr <> '' then
TL.Add(sourcestr);
until sourcestr = '';
for i := 0 to TL.Count - 1 do begin
sourcestr := TL[i];
// process sourcestr however you want
end;
TL.Free;
though you could, of course, simply process sourcestr as you go along, in the repeat..until loop.

why does computer print a value which is out of range of string in pascal?

In pascal programming language i wrote the following code
Program practice;
//**** Function to get back N characters from a P position from a given string
Function get_char(s1:String;n,p :Integer): String;
Var
temp : String;
i : Integer;
Begin
temp:= s1[p];
For i:= p+1 To p+n-1 Do
temp := temp + s1[i];
get_char := temp;
End;
//**** end of the function *****
Var
s1,s2: String;
n,p: Integer;
Begin
Write('Enter the number of char:');
readln(n);
write('Enter the position:' );
readln(p);
write('Enter the string : ');
readln(s1);
write(get_char(s1,n,p));
Readkey;
End.
Know that this function gets back a certain number of characters given by the user from a certain postion in the string .
for example 'hello' with p = 1 and n =2 the result will be 'he' .
Now imagine p is 3 and n =4 then then the output of the function will be 'lloA'.
So my question is what happends in this case or why do we get such a result ? ( please give me details if its related to memory).
When your function reads characters beyond the end of the string, it reads memory content that happens to be in those memory positions, and interpretes that memory content as characters. Memory content beyond the length of a string is not defined, nor predictable. Some compilers add an explicit Char(0) as a terminating character. This zero character is not included in the length of the string.
To prevent wrong return values form your function, you can either,
a) turn range checking on in compiler settings, which will raise runtime errors
b) check that p + n - 1 <= Length(s) and if not, limit reading to Length(s).
Selecting option b gives a freedom to read until the end of any string by passing MaxInt for argument p.

How to remove spaces from string with while do operator? Pascal

I have text and I need to remove spaces from beginning of text and from end of text. And I can do it only with while do operator. How can I do that? Here's program code
program RandomTeksts;
uses crt;
var
t:String;
l, x, y:Integer;
const tmin=1; tmax=30;
label
Start,
end;
begin
Start:
clrscr;
writeln('write text (from ',tmin,' to ',tmax,' chars): ');
readln(t);
l:=length(t);
if (l<tmin) or (l>tmax) then
begin
writeln('Text doesn't apply to rules!');
goto end;
end;
clrscr;
begin
randomize;
repeat
x:=random(52+1);
y:=random(80+1);
textcolor(white);
gotoxy(x,y);
writeln(t);
delay(700);
clrscr;
until keypressed;
end;
ord (readkey)<>27 then
goto Start;
end:
end.
Academic problem: Remove leading and trailing spaces from a string using a while loop.
How do we approach this problem?
Well, we certainly would like to create a function that trims a string. This way, we can simply call this function every time we need to perform such an operation. This will make the code much more readable and easier to maintain.
Clearly, this function accepts a string and returns a string. Hence its declaration should be
function Trim(const AText: string): string;
Here I follow the convention of prefixing arguments by "A". I also use the const prefix to tell the compiler I will not need to modify the argument within the function; this can improve performance (albeit very slightly).
The definition will look like this:
function Trim(const AText: string): string;
begin
// Compute the trimmed string and save it in the result variable.
end;
A first attempt
Now, let's attempt to implement this algorithm using a while loop. Our first attempt will be very slow, but fairly easy to follow.
First, let us copy the argument string AText to the result variable; when the function returns, the value of result will be its returned value:
result := AText;
Now, let us try to remove leading space characters.
while result[1] = ' ' do
Delete(result, 1, 1);
We test if the first character, result[1], is a space character and if it is, we use the Delete procedure to remove it from the string (specifically, Delete(result, 1, 1) removes 1 character from the string starting at the character with index 1). Then we do this again and again, until the first character is something other than a space.
For example, if result initially is ' Hello, World!', this will make it equal to 'Hello, World!'.
Full code, so far:
function Trim(const AText: string): string;
begin
result := AText;
while result[1] = ' ' do
Delete(result, 1, 1);
end;
Now try this with a string that consists only of space characters, such as ' ', or the empty string, ''. What happens? Why?
Think about it.
Clearly, in such a case, result will sooner or later be the empty string, and then the character result[1] doesn't exist. (Indeed, if the first character of result would exist, result would be of length at least 1, and so it wouldn't be the empty string, which consists of precisely zero characters.)
Accessing a character that doesn't exist will make the program crash.
To fix this bug, we change the loop to this:
while (Length(result) >= 1) and (result[1] = ' ') do
Delete(result, 1, 1);
Due to a technique known as 'lazy boolean evaluation' (or 'short-circuit evaluation'), the second operand of the and operator, that is, result[1] = ' ', will not even run if the first operand, in this case Length(result) >= 1, evaluates to false. Indeed, false and <anything> equals false, so we already know the value of the conjunction in this case.
In other words, result[1] = ' ' will only be evaluated if Length(result) >= 1, in which case there will be no bug. In addition, the algorithm produces the right answer, because if we eventually find that Length(result) = 0, clearly we are done and should return the empty string.
Removing trailing spaces in a similar fashion, we end up with
function Trim(const AText: string): string;
begin
result := AText;
while (Length(result) >= 1) and (result[1] = ' ') do
Delete(result, 1, 1);
while (Length(result) >= 1) and (result[Length(result)] = ' ') do
Delete(result, Length(result), 1);
end;
A tiny improvement
I don't quite like the space character literals ' ', because it is somewhat difficult to tell visually how many spaces there are. Indeed, we might even have a different whitespace character than a simple space. Hence, I would write #32 or #$20 instead. 32 (decimal), or $20 (hexadecimal), is the character code of a normal whitespace.
A (much) better solution
If you try to trim a string containing many million of characters (including a few million leading and trailing spaces) using the above algorithm, you'll notice that it is surprisingly slow. This is because we in every iteration need to reallocate memory for the string.
A much better algorithm would simply determine the number of leading and trailing spaces by reading characters in the string, and then in a single step perform a memory allocation for the new string.
In the following code, I determine the index FirstPos of the first non-space character in the string and the index LastPos of the last non-space character in the string:
function Trim2(const AText: string): string;
var
FirstPos, LastPos: integer;
begin
FirstPos := 1;
while (FirstPos <= Length(AText)) and (AText[FirstPos] = #32) do
Inc(FirstPos);
LastPos := Length(AText);
while (LastPos >= 1) and (AText[LastPos] = #32) do
Dec(LastPos);
result := Copy(AText, FirstPos, LastPos - FirstPos + 1);
end;
I'll leave it as an exercise for the reader to figure out the precise workings of the algorithm. As a bonus exercise, try to benchmark the two algorithms: how much faster is the last one? (Hint: we are talking about orders of magnitude!)
A simple benchmark
For the sake of completeness, I wrote the following very simple test:
const
N = 10000;
var
t: cardinal;
dur1, dur2: cardinal;
S: array[1..N] of string;
S1: array[1..N] of string;
S2: array[1..N] of string;
i: Integer;
begin
Randomize;
for i := 1 to N do
S[i] := StringOfChar(#32, Random(10000)) + StringOfChar('a', Random(10000)) + StringOfChar(#32, Random(10000));
t := GetTickCount;
for i := 1 to N do
S1[i] := Trim(S[i]);
dur1 := GetTickCount - t;
t := GetTickCount;
for i := 1 to N do
S2[i] := Trim2(S[i]);
dur2 := GetTickCount - t;
Writeln('trim1: ', dur1, ' ms');
Writeln('trim2: ', dur2, ' ms');
end.
I got the following output:
trim1: 159573 ms
trim2: 484 ms

How to convert integer to array of bytes?

I have sort of action listener in ST code (similar to Pascal), where it returns me an integer. Then i have a CANopen function, which allows me to send data only in Array of bytes. How can i convert from these types?
Thanks for answer.
You can use the Move standard function to block-copy the integer into an array of four bytes:
var
MyInteger: Integer;
MyArray: array [0..3] of Byte;
begin
// Move the integer into the array
Move(MyInteger, MyArray, 4);
// This may be subject to endianness, use SwapEndian (and related) as needed
// To get the integer back from the array
Move(MyArray, MyInteger, 4);
end;
PS: I haven't coded in Pascal for a few months now so there might be mistakes, feel free to fix.
Here are solutions working with Free Pascal.
First, with "absolute":
var x: longint;
a: array[1..4] of byte absolute x;
begin
x := 12345678;
writeln(a[1], ' ', a[2], ' ', a[3], ' ', a[4])
end.
With pointers:
type tarray = array[1..4] of byte;
parray = ^tarray;
var x: longint;
p: parray;
begin
x := 12345678;
p := parray(#x);
writeln(p^[1], ' ', p^[2], ' ', p^[3], ' ', p^[4])
end.
With binary operators:
var x: longint;
begin
x := 12345678;
writeln(x and $ff, ' ', (x shr 8) and $ff, ' ',
(x shr 16) and $ff, ' ', (x shr 24) and $ff)
end.
With record:
type rec = record
case kind: boolean of
true: (int: longint);
false: (arr: array[1..4] of byte)
end;
var x: rec;
begin
x.int := 12345678;
writeln(x.arr[1], ' ', x.arr[2], ' ', x.arr[3], ' ', x.arr[4])
end.
You can also use a variant record, which is the traditional method of deliberately aliasing variables in Pascal without using pointers.
type Tselect = (selectBytes, selectInt);
type bytesInt = record
case Tselect of
selectBytes: (B : array[0..3] of byte);
selectInt: (I : word);
end; {record}
var myBytesInt : bytesInt;
The nice thing about the variant record is that, once you set it up, you can freely access the variable in either form without having to call any conversion routines. For example "myBytesInt.I:=$1234" if you want to access it as an integer, or "myBytesInt.B[0]:=4" etc if you want you access it as a byte array.
You can do something like this :
byte array[4];
int source;
array[0] = source & 0xFF000000;
array[1] = source & 0x00FF0000;
array[2] = source & 0x0000FF00;
array[3] = source & 0x000000FF;
Then if you glue array[1] to array[4] together you will get your source integer;
Edit : corrected the mask.
Edit : As Thomas pointed out in the comments -> you still have to bit shift the resulting value of ANDing to LSB to get correct values.

Resources