I want to encrypt a message with a simple Vigenere cipher by assigning each letter in the alphabet a numeric value e.g. A= 1; B= 2;..Z= 26. The problem is I don't know which function to use to recognize a character in a string(as it is a message that has to be encoded, complete with spaces), and then giving it a specific, numeric value.
Next up, that numeric message has to be converted into binary, which is easy, but how do I convert that message that was a string into an integer(other that the StrToInt function)?
I just need to know which function to use for the Vigenere Cipher.
*I am still in High school so I apologize in advance for using the wrong terms.
You can use a case statement to perform the encoding.
function EncodedChar(C: Char): Byte;
begin
case C of
'A'..'Z':
Result := 1 + ord(C) - ord('A');
' ':
Result := ???;
',':
Result := ???;
... // more cases here
else
raise ECannotEncodeThisCharacter.Create(...);
end;
end;
Encode a string with a for loop:
function EncodedString(const S: string): TBytes;
var
i: Integer;
begin
SetLength(Result, Length(S));
for i := 1 to Length(S) do begin
// dynamic arrays are 0-based, strings are 1-based, go figure!
Result[i-1] := EncodedChar(S[i]);
end;
end;
Related
I have a very weird situation.
This is the JSON I am trying to parse:
[
{
"username":"xxx",
"email":"xxx#gmail.com",
"custom_title":"xxx title",
"timezone":"Africa\/Cairo",
"message_count":"218",
"alerts_unread":"0",
"like_count":"385",
"friend_count":"0"
}
]
This is my parsing code:
type
TUserData = record
email, timezone: string;
msg, alerts, likes: integer;
end;
procedure TDMRest.parseData(var b: TUserData);
var
jtr: TJsonTextReader;
sr: TStringReader;
begin
//RESTResponseLogin.Content has the above json text
sr := TStringReader.Create(RESTResponseLogin.Content);
try
jtr := TJsonTextReader.Create(sr);
try
while jtr.Read do
begin
if jtr.TokenType = TJsonToken.StartObject then
process(b, jtr);
end;
finally
jtr.Free;
end;
finally
sr.Free;
end;
end;
//here there is a problem
procedure TDMRest.process(var c: TUserData; jtr: TJsonTextReader);
begin
while jtr.Read do
begin
if (jtr.TokenType = TJsonToken.PropertyName) then
begin
if jtr.Value.ToString = 'email' then
begin
jtr.Read;
c.email := jtr.Value.AsString;
end;
if jtr.Value.ToString = 'timezone' then
begin
jtr.Read;
c.timezone := jtr.Value.AsString;
end;
if jtr.Value.ToString = 'message_count' then
begin
jtr.Read;
c.msg := jtr.Value.AsInteger;
end;
if jtr.TokenType = TJsonToken.EndObject then
begin
c.alerts := 0;
c.likes := 0;
exit;
end;
end;
end;
end;
MY PROBLEM: In the process() code, the first 2 if blocks (email and timezone) can read values into my record. But when I add other if blocks (like if jtr.Value.ToString = 'message_count' then), I cannot see the values of my record anymore.
Am I parsing the data properly?
Basically, I need to grab the info from a JSON string and put the data inside a TUserData record.
I have found the above pattern in a book titled "Expert Delphi", and I am pretty sure that the parseData() function is correct. Probably I am missing something in the process.
The TDMRrst is a DataModule; I am giving the function a record, and I'd like the data to be properly parsed.
What is wrong here?
In the JSON you have shown, all of the values are strings, there are no integers. So, when you call jtr.Value.AsInteger for the message_count value, it raises a conversion exception that you are not catching. TValue.AsInteger DOES NOT perform an implicit conversion from string to integer for you.
You will have to use jtr.Value.AsString instead and convert the string to an integer using StrToInt():
if jtr.Value.ToString = 'message_count' then
begin
jtr.Read;
//c.msg := jtr.Value.AsInteger;
c.msg := StrToInt(jtr.Value.AsString);
end;
Do the same for the other "integer" values in the JSON (alerts_unread, like_count, and friend_count).
How to compare string to integer using while loop in Pascal?
Like this:
var Destination:string;
while (Destination>'11') do begin
writeln('Error');
write('Destination Number');
readln(Destination);
end;
You have to convert Destination to an integer:
program Project1;
uses sysutils;
var
converted: integer;
Destination: string;
begin
converted := 12;
Destination := '';
while (converted > 11) do
begin
writeln('Error');
writeln('Destination Number');
readln(Destination);
converted := StrToIntDef(Destination, 12);
end;
end.
convertion routines are avalaible in sysutils:
http://www.freepascal.org/docs-html/rtl/sysutils/index-5.html
Why not just do the conversion in the WHILE--DO statement?
ReadLn(Destination);
WHILE StrToInt(Destination) > 11 DO NumberIsTooHigh;
where NumberIsTooHigh simply is a procedure you write to handle your "error". Ex:
PROCEDURE NumberIsTooHigh;
BEGIN
WriteLn('Your number is above valid range');
write('Destination Number');
readln(Destination);
END;
The reason for the previous routine to make "error" on the first run is that "Destination" does not yet have a value at all. The converted-variable is then set manually to 12, just outside the Ok-range, hence it will always produce the error on startup.
I'm trying to catch the following JSON array :
[{"name":"Bryan","email":"Bryan#hotmail.com"},
{"name":"Louis","email":"Louis#hotmail.com"},
{"name":"Maria","email":"Maria#hotmail.com"},
{"name":"Test","email":"test#hotmail.com"},
{"name":"Anthony","email":"anthony#hotmail.com"}]
and put it in Memo or ListBox in Delphi :
the code is the following :
procedure TForm1.Button1Click(Sender: TObject);
var jv: TJSONValue;
jo: TJSONObject;
jp: TJSONPair;
ja: TJSONArray;
i: integer;
j: integer;
begin
RESTRequest1.Execute;
jv:=RESTResponse1.JSONValue;
jo:= TJSONObject.ParseJSONValue(jv.ToString) as TJSONObject;
try
for i := 0 to jo.Size - 1 do
begin
jp := jo.Get(i);
if jp.JsonValue is TJSONArray then
begin
ja := jp.JsonValue as TJSONArray;
for j := 0 to ja.Size -1 do
Memo1.Lines.Add(ja.Get(i).ClassName + ': ' + ja.Get(j).ToString);
end
else
Memo1.Lines.Add(jp.ClassName + ': '+ jp.ToString);
end;
finally
jo.Free;
end;
end;
When I click in Button I got the following error message :
Invalid class typecast
during debugging the following line has a problem :
jo:= TJSONObject.ParseJSONValue(jv.ToString) as TJSONObject;
I don't know how to resolve this problem or this mistake ,
Could you please help me ?
Thanks.
This could perfectly well be worked out by reading the code and looking at the JSON. However, I'd like to show you how to go about debugging such a problem in case you cannot work it out by static analysis. When an as cast fails that is always because the object on the left hand side of the as does not derive from the type on the right hand side. The next step then is always to inquire as to what the type of the object on the left hand side is. I've included a short MCVE above as a means to demonstrate.
The output of this program:
{$APPTYPE CONSOLE}
uses
System.JSON;
const
JSON = '[{"name":"Bryan","email":"Bryan#hotmail.com"},' +
' {"name":"Louis","email":"Louis#hotmail.com"},' +
' {"name":"Maria","email":"Maria#hotmail.com"},' +
' {"name":"Test","email":"test#hotmail.com"},' +
' {"name":"Anthony","email":"anthony#hotmail.com"}]';
begin
Writeln(TJSONObject.ParseJSONValue(JSON).ClassName);
end.
is
TJSONArray
Now, TJSONArray does not derive from TJSONObject. Hence your as cast raise a runtime error. If you cast the value returned by ParseJSONValue to TJSONArray that will succeed.
This is to be expected since the root of your JSON is an array and is not an object.
You need to modify your code so that it does not assume that the root level is always an object. You need different behaviour for arrays and objects.
I'm not sure what the problem of TJSONObject is with the string you posted.
For some reason it will parse it if you changed it.
{"Persons":[{"name":"Bryan","email":"Bryan#hotmail.com"},{"name":"Louis","email":"Louis#hotmail.com"},{"name":"Maria","email":"Maria#hotmail.com"},{"name":"Test","email":"test#hotmail.com"},{"name":"Anthony","email":"anthony#hotmail.com"}]}
If I run the code as it is I get the following result
If you don't mind using something different than default Delphi units I would suggest superobject (Link here)
superobject will parse your JSON edited and as posted.
Your code would look like this:
Const
MyJSON = '[{"name":"Bryan","email":"Bryan#hotmail.com"},{"name":"Louis","email":"Louis#hotmail.com"},{"name":"Maria","email":"Maria#hotmail.com"},{"name":"Test","email":"test#hotmail.com"},{"name":"Anthony","email":"anthony#hotmail.com"}]';
procedure ParseJSON;
var
obj: ISuperObject;
Ar: TSuperArray;
I: integer;
begin
obj := SO(MyJSON);
if obj.IsType(stArray) then
begin
Ar := obj.AsArray;
try
for I := 0 to Ar.Length-1 do
L.Add(Ar.O[I].AsString);
finally
Ar.Free;
end;
end
else
L.Add(Obj.AsString);
end;
Result:
For Koul, to get the element names and values.
Like I said not very pretty code but ok.
Ar.O[0].AsObject.GetNames.AsArray.S[0]
To cut it up in pieces a bit.
Ar.O[0] //Get the first element in the array as ISuperObject
.AsObject //Get it as TSuperTableString
.GetNames //Gets all names in the array, in this case "name" and "email"
.AsArray[0]//Get the first name in the names array.
It will result in email (Names are sorted A-Z)
You can do the same for the values by calling GetValues instead of GetNames.
I think the prettiest way to get it will be defining 2x more TSuperArray
procedure PrintNamesAndValues;
Var
Ar, ArNames, ArValues:TSuperArray;
I: Integer;
begin
Ar := SO(<JSON string>).asArray;
ArNames := Ar.O[0].AsObject.GetNames.AsArray;
ArValues := Ar.O[0].AsObject.GetValues.AsArray;
For I := 0 to ArNames.Length-1 do
WriteLn(Format('%s: %s',[ArNames.S[I], ArValues.S[I]]));
end;
Hope it's all clear enough :)
I keep getting a error when i run this code, What wrong with the code?
create or replace function f_vars(line varchar2,delimit varchar2 default ',')
return line_type is type line_type is varray(1000) of varchar2(3000);
sline varchar2 (3000);
line_var line_type;
pos number;
begin
sline := line;
for i in 1 .. lenght(sline)
loop
pos := instr(sline,delimit,1,1);
if pos =0 then
line_var(i):=sline;
exit;
endif;
string:=substr(sline,1,pos-1);
line_var(i):=string;
sline := substr(sline,pos+1,length(sline));
end loop;
return line_var;
end;
LINE/COL ERROR
20/5 PLS-00103: Encountered the symbol "LOOP" when expecting one of
the following:
if
22/4 PLS-00103: Encountered the symbol "end-of-file" when expecting
one of the following:
end not pragma final instantiable order overriding static
member constructor map
Stack Overflow isn't really a de-bugging service.
However, I'm feeling generous.
You have spelt length incorrectly; correcting this should fix your first error. Your second is caused by endif;, no space, which means that the if statement has no terminator.
This will not correct all your errors. For instance, you're assigning something to the undefined (and unnecessary) variable string.
I do have more to say though...
I cannot over-emphasise the importance of code-style and whitespace. Your code is fairly unreadable. While this may not matter to you now it will matter to someone else coming to the code in 6 months time. It will probably matter to you in 6 months time when you're trying to work out what you wrote.
Secondly, I cannot over-emphasise the importance of comments. For exactly the same reasons as whitespace, comments are a very important part of understanding how something works.
Thirdly, always explicitly name your function when ending it. It makes things a lot clearer in packages so it's a good habit to have and in functions it'll help with matching up the end problem that caused your second error.
Lastly, if you want to return the user-defined type line_type you need to declare this _outside your function. Something like the following:
create or replace object t_line_type as object ( a varchar2(3000));
create or replace type line_type as varray(1000) of t_line_type;
Adding whitespace your function might look something like the following. This is my coding style and I'm definitely not suggesting that you should slavishly follow it but it helps to have some standardisation.
create or replace function f_vars ( PLine in varchar2
, PDelimiter in varchar2 default ','
) return line_type is
/* This function takes in a line and a delimiter, splits
it on the delimiter and returns it in a varray.
*/
-- local variables are l_
l_line varchar2 (3000) := PLine;
l_pos number;
-- user defined types are t_
-- This is a varray.
t_line line_type;
begin
for i in 1 .. length(l_line) loop
-- Get the position of the first delimiter.
l_pos := instr(l_line, PDelimiter, 1, 1);
-- Exit when we have run out of delimiters.
if l_pos = 0 then
t_line_var(i) := l_line;
exit;
end if;
-- Fill in the varray and take the part of a string
-- between our previous delimiter and the next.
t_line_var(i) := substr(l_line, 1, l_pos - 1);
l_line := substr(l_line, l_pos + 1, length(l_line));
end loop;
return t_line;
end f_vars;
/
In this FreePascal code I write, I found that in a dynamic array of length 'n', it always contained a random value in element 'n'.
I understand why that is, however, I am wondering if perhaps there is a flaw in the way i've written my code. I've pasted it below. I'd welcome any corrections.
program LinearSearch;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils
{ you can add units after this };
{$R *.res}
type
ArrayOfByte = array of Byte;
Function findMaximum(studentMarks : ArrayOfByte; numberOfStudents : integer)
: integer;
var
maximumMark : Integer;
studentWithMaximumMark : Integer;
index : integer;
begin
setLength(studentMarks, numberOfStudents);
maximumMark := studentMarks[0];
for index:=0 to numberOfStudents do
begin
write(IntToStr(studentMarks[index]));
if index = numberOfStudents then writeln('.')
else write(',');
end;
for index:= 0 to (numberOfStudents - 1) do
begin
if studentMarks[index] > maximumMark then
begin
maximumMark := studentMarks[index];
studentWithMaximumMark := index;
end;
end;
write('Maximum score of ',IntToStr(maximumMark),' was achieved by ');
Result := studentWithMaximumMark+1;
end;
var
studentMarks : ArrayOfByte;
numberOfStudents : Integer;
studentWithMaximumMarks : Integer;
counter : integer;
begin
write('Enter the number of students: ' );
readln(numberOfStudents);
setLength(studentMarks,numberOfStudents);
writeln('Input the grades for the following students:');
for counter := 0 to (numberOfStudents - 1) do
begin
write('Student ',counter+1,': ');
readln(studentMarks[counter]);
end;
writeln('Data has been input. Finding student with maximum marks.');
studentWithMaximumMarks := findMaximum(studentMarks,numberOfStudents);
write('student no. ',IntToStr(studentWithMaximumMarks));
writeln;
writeln('Press ANY key to continue');
readln;
end.
In Free Pascal dynamic arrays are zero based. So the first element is MyArray[0] and last element is MyArray[High(MyArray)] which is equal to MyArray[Length(MyArray) - 1]. You should never access MyArray[Length(MyArray)].
...I found that in a dynamic array of length 'n', it always contained a random value in element 'n'. this is because you are accessing a value beyond of the bounds of the array, check in the procedure findMaximum the line
for index:=0 to numberOfStudents do
must be
for index:=0 to numberOfStudents-1 do
Also you can remove the first line of the same procedure setLength(studentMarks, numberOfStudents);