TStringList problem with values at index - delphi

So I have several summary files that I want to read and get the values from.
I am doing the following:
OutputSummary := TStringList.Create;
for idx := 0 to 82 do
OutputSummary.Insert(idx, '');
to initialize the values I'm using
then, I have a loop:
for idx := 0 to SummaryFiles.Count - 1 do
begin
AssignFile(finp, SummaryFiles[idx]);
ReSet(finp);
for ndx := 0 to 5 do
ReadLn(finp, buff);
for ndx := 0 to 82 do
begin
ReadLn(finp, buff);
temp := GetToken(buff, ' ');
buff := GetRemains(buff, '|');
temp := GetToken(buff, '|');
valuestring := OutputSummary[ndx] + delimiter + temp;
OutputSummary.Insert(ndx, valuestring);
end;
CloseFile(finp);
end;
The first 0 to 5 loop skips the lines I don't want to read, and the 0 to 82 reads lines that look like
1. Initial Wait List|1770
So I was debugging the program to see how it works with just 2 SummaryFiles.
The first time through, it works perfectly. The line is read correctly, I get the value and when I insert valuestring, it looks like ",1770" (for example), and I can also highlight OutputSummary[ndx] after the insert command and see that the value was inserted correctly.
Then I open the second file, which also works fine until the line
valuestring := OutputSummary[ndx] + delimiter + temp;
the first time, OutputSummary[0] is correct and the correct line is added.
However, OutputSummary[1] through OutputSummary[82] is the same as OutputSummary[0]! This makes no sense since when I was first adding those values, I could see that OutputSummary[1] through 82 were unique and correct.
Can anyone see a problem? Is it a debugger error? Am I just missing something obvious that I don't see?
thanks

It looks to me like you're trying to create a table of some sort, with one column per input file and one row per line in the file, with the columns separated by the delimiter. If so, calling .Insert on the string list isn't going to quite work right, since you'll end up inserting 83 * SummaryFiles.Count rows.
Instead of the Insert call, you need something like this:
if OutputSummary.count > ndx then
OutputSummary[ndx] := valuestring
else OutputSummary.Add(valuestring);
See if that helps.
Also, you might want to consider replacing the "magic number" 82 with a meaningful constant, like const LINES_TO_READ = 82. That makes it easier to read the code and understand what it's supposed to be doing.

Related

Delete text before specific character in delphi

Help
I have many strings, I want to keep string after symbol /, they are like:
63728/4817847 become 4817847 ,
345/7895 become 7895 ,
1289/98721 become 98721 ,
1876789/987 become 987 .
I still have not found a way, because the number of strings to be stored or to be deleted is changing every time.
Thanks.
You can do this easily using a combination of Pos and Copy.
Source := '1876789/987';
// Find position of `/` in the string
Index := Pos('/', Source);
if Index > 0 then
// Extract portion of string following the '/' (the + 1) to the end
Source := Copy(Source, Index + 1, Length(Source));
As SilverWarior pointed out in a comment, you could also use System.Delete.
Source := '1876789/987';
System.Delete(Source, 1, Pos('/', Source));

Searching i TStringList using POS - need more advanced method

I use the following function to search a TStringList I am reading from a file.
I know that when I search a value, then the return value I need is always on the line after the one with the item I search.
It has always worked using POS to search, but now the file has been expanded and I have to look for 2 items 'Adresse' and 'Adresse 2'
That gives me an issue since pos finds 'Adresse' in both cases and my data is then wrong.
Is there another method of searching a string for a substring that I don't know of or do I have to make my own.
function FindValue(const aFilename, aSearch: string): string;
var
InfoList: TStringList;
Counter: integer;
begin
InfoList := TStringList.Create;
try
InfoList.LoadFromFile(aFilename);
if InfoList.Count > 0 then
for Counter := 0 to InfoList.Count - 1 do
begin
if Pos(aSearch, Infolist.Strings[Counter]) > 0 then
Result := Infolist.Strings[Counter + 1]
end
else
Result := '';
finally
InfoList.Free;
end;
end;
For info: the input to the TStringList comes from a textfile extracted from a HTML file.
A sample of a file could be:
OZ8HP
Hugo Pedersen
Radioamatør
Nykøbing M
Sendeposition:
Adresse:
Prinsensvej 18
Postnummer:
7900
Bynavn:
Nykøbing M
Antenne højde (m):
Kote (m):?Kote (m):Brugerens/tilladelsesindehaverens øvrige adresseoplysninger så som Stednavn og/eller Postboks. Hjælpetegnet * kan anvendes, som beskrevet i hjælp.
Koordinater:
Geografisk anvendelse:
Frekvensmaske:
Tekniske specifikationer:
Sendeeffekt basisstation:
Sendeeffekt mobile anlæg:
Båndbredde (MHz):
Antal anlæg:
MMSI:
Kaldesignaltype:
Personlig
Frekvenskategori:
Udstedelses-metode:
Intention om overdragelse:
Nej
Udløbsdato:
Brugerdata:
Brugernummer:
956078
Adresse:
Prinsensvej 18
Adresse 2:
Sejerslev
Postnr.:
7900
Bynavn:
Nykøbing M
Kaldesignal-kategori:
Bestået A
It looks to me as though the real mistake is being too lax in your search. Why accept partial matches? It would seem more robust to look for complete matches
if SameText(aSearch, Infolist[Counter]) then
or perhaps to account for leading and trailing whitespace:
if SameText(aSearch, Trim(Infolist[Counter])) then
You'd need to pass 'Adresse:' or 'Adresse 2:' as the search string, or add the colon in the search function.
Use AnsiSameText if you want locale sensitive comparison. Use = if you want case sensitive comparison, etc.
You might pass multiple search strings and be able to loop only once over the file. As it stands you read it twice which seems wasteful. Indeed surely better to operate on a string list and not be coupled to file storage.
You return the last match in the data rather than the first, for instance. What if there are multiple matches? Does your code behave as intended?
You should also be aware that if no match is found your function does not assign to the Result variable which means it is undefined.

Delphi TValueListEditor Strings prop-ed quirk?

Investigating odd behaviour of a TValueListEditor being used to generate a filter
expression for a ClientDataSet, I've traced it to a situation where if the first entry
in it apparently had nothing in the Value column, it returned #13#10 as the Value, rather than
''.
In the following, the TStringlist TL is initialized with the same contents as the ValueListEditor
Strings property has in my app. The Assert does not fail for the TStringlist, but it does for the
ValueListEditor. These results occurred with D7 and XE4.
procedure TDefaultForm.ApplyFilter;
var
i,
Max : Integer;
Key,
Value : String;
TL : TStringlist;
begin
TL := TStringlist.Create;
try
TL.Add('Country=');
TL.Add('Class=CON');
for i:= 0 to TL.Count - 1 do begin
Key := TL.Names[i];
Value := TL.Values[Key];
Assert(Value <> #13#10); // succeeds for all i
end;
Max := ValueListEditor1.RowCount;
for i:= 1 to Max do begin
Key := ValueListEditor1.Keys[i];
Value := ValueListEditor1.Values[Key];
// Value := ValueListEditor1.Strings.ValueFromIndex[i-1];
Assert(Value <> #13#10); //Fails for i = 1!
end;
finally
TL.Free;
end;
end;
Btw, the TVLE was set up entirely in the Object Inspector: I simply dragged a TVLE off the palette, clicked Strings in the OI, clicked in the LH cell and typed 'Country' (sans quotes), pressed the Down key and typed 'Class' then right-arrow and typed 'CON'.
Obviously, I could avoid this by Value := Trim(Value), but was curious where the #13#10 was coming from.
Update: Prompted by #Deltic's answer and helpful comments, I decided to re-trace my steps and added another TVLE to my form. The following extracts from the DFM are revealing:
object ValueListEditor1: TValueListEditor
Left = 16
Top = 224
Width = 306
Height = 135
KeyOptions = [keyEdit, keyAdd]
Strings.Strings = (
'Country='#13#10
'Class=CON')
TabOrder = 2
end
[...]
object ValueListEditor2: TValueListEditor
Left = 440
Top = 192
Width = 306
Height = 246
KeyOptions = [keyEdit, keyAdd]
Strings.Strings = (
'A='
'B=ValueOfB')
TabOrder = 5
end
So, with hindsight, my question really boils down to how did the #13#10 get into the DFM? And then it came back to me ...
With no previous experience of the TVLE, when I set up the form, I got stuck at the point where I needed to add a second row. I tried pressing [Enter], but that did nothing, so then I tried Ctrl-Enter and that did nothing either. But repeating the exercise now has confirmed that that's how the CR/LF got into the TVLE's Strings.
So, it seems that the answer to my q is "No, the TVLE isn't broken, but its Strings property editor
has a quirk regarding Ctrl-Enter". In other circs, I would consider deleting my q, seeing as it's at least partly caused by operator aberration, but perhaps it's better left to assist any others who trip over the same point.
Update #2 I see that my curiousity has earned me a -1. Fair enough, but I'm still inclined to leave this q & a in place, if only as an illustration of the fact that problems have deterministic causes, which can often be identified by simple things such as re-tracing one's steps, particularly with someone obviously knowledgeable looking over one's shoulder, as it were. Perhaps the down-voter would care to enlighten readers what help to future readers such a silent -1 is.
You have not shown how your value list editor is initialised, and I suspect that this is where your problem is. Behind a TValueListEditor is nothing more than a TStringList (strictly speaking a subclass of one, but the subclass doesn't change the fundamental behaviour w.r.t named values).
If your apparently empty value in the value list is yielding a value of #13#10 then it must be because that is the actual value that it has.
This simple test snippet verifies this:
var
i:Integer;
k, v:String;
begin
ed.InsertRow('Country', '', TRUE);
ed.InsertRow('Class', 'CON', TRUE);
for i:= 1 to ed.RowCount - 1 do
begin
k := ed.Keys[i];
v := ed.Values[k];
ASSERT(v <> #13#10); // Never fails
end;
end;
Where ed is a TValueListEditor on the form.
Replace the first line of code in the above snippet with this however:
ed.InsertRow('Country', #13#10, TRUE);
And the ASSERT() fails.
I suggest you investigate the initialisation of your value list editor. My guess is that it is being populated by reading from a file using a mechanism which is reading the entire line into a string, including the line end sequences, and the code that is adding the values for each read line is not stripping the #13#10 line terminators, resulting in the values being added as <name>=<value>#13#10 in each case.

Can I use an If statement inside a While statement?

while not eof(MyFile) do
begin
Readln(MyFile,sLine);
iCheck := pos('*',sLine);
if iCheck >= 0 then
K := K + 1;
else
K := 1;
sLine := sArrayParty[K];
end;
K is my counter. MyFile is set to a textfile.
I am trying to run an if statement inside a while statement to check if there is a * in a line read into sLine. If so, I want my counter to be incremented, thereby putting the following text into the next index of the array. So basically I have a text file with information separated by * as delimiters and I want each piece of information to populate a new index. But delphi spases everytime I put that if statement in.
You have a clear syntax error in your code, and the compiler explains exactly what it is:
[DCC Error] Unit1.pas(22): E2153 ';' not allowed before 'ELSE'
So read the words the error message contain, and remove the ; before the else:
if iCheck > 0 then
K := K + 1
else
K := 1;
The number in parenthesis after the Unit1.pas (in my example, (22) is the exact line number where the compiler stopped working, so the line before the else would be line 21. The line numbers at the bottom of the editor window tell you what line that is clearly.
if there is no '' then the pos function will return 0,
if there is '' then it will return the first occurance position.
if iCheck >= 0 then
should be changed to if iCheck > 0 then
i do remember we can assign the string to a string list and assign the stringlist's delimiter property to '*'
ie.
strlst.delimiter := '*';
strlst.text := sline;
so u can get each string traversing through the strlst...
(i used this long back,and i dont have delphi now to test it,please correct me if any thing is wrong)

Algol60 passing integer element of array as parameter - error bad type

I have following problem.
When I try to run the code with arun file.obj (I have compiled with algol.exe file)
BEGIN
INTEGER PROCEDURE fun(tab,index,lower,upper);
INTEGER tab,index,lower,upper;
BEGIN
INTEGER t;
text (1, "Start");
t := 0;
FOR index := lower STEP 1 UNTIL upper DO
t := t + tab;
fun := t;
END;
INTEGER ARRAY t[1:10];
INTEGER i,result,lower,upper;
lower := 1;
upper := 10;
FOR i := 1 STEP 1 UNTIL 10 DO
t[i] := i;
i := 1;
result := fun(t[i],i,lower,upper);
END FINISH;
I am still getting error:
ERROR 3
ADD PBASE PROC LOC
07D4 0886 1 13
083A 0842 0 115
The compiler I use is "The Rogalgol Algol60" product of RHA (Minisystems) Ltd.
Error 3 means "3 Procedure called where the actual and the formal parameter types do not match."
But I do not understand why. The reason of error is t[i] (If I change to i - it is ok).
Someone knows what I am doing wrongly?
I compile the code on the dosbox (linux)
Problem is that the index of the integer array that you're passing to your procedure isn't the same as the integer that he's expecting. I can't remember what an integer array is full of, but I guess it isn't integers... Have to admit I never use them, but can't remember why. Possibly because of limitations like this. I stick to Real arrays and EBCDIC ones.
You can almost certainly fix it by defining a new integer, j; inserting "j := t[i];" before your invocation of 'fun'; then invoking 'fun' with 'j' rather than t[i].
BTW you may want to make the array (and the 'for' loop) zero-relative. ALGOL is mostly zero-relative and I think it may save memory if you go with the flow.
Let me know if this helps....

Resources