Stringlist with delimiter as a string? - delphi

I have an attribute called HistoryText in a object that is stored as a string.
I want to show all rows in a grid. I should be able to delete and edit rows in the grid.
The format is:
16.5.2003-$-12:09-$-anna-$-Organization created
2.6.2005-$-13:03-$-jimmy-$-Organization edited
19.12.2005-$-13:33-$-madeleine-$-Organization edited
So each row have 4 fields, date, time, user, and message with a delimiter string as '-$-'.
As the delimiter a string and not a char it cannot be assigned to the stringlists delimiter property.
I have a routine to extract the string to a Stringlist:
procedure ParseDelimited(const aStringList: TStringList; const aOrgList, aDelimiter: string);
var
vDelimiterPos : integer;
vPartialStr : string;
vRemaingTxt : string;
vDelimiterLength : integer;
begin
vDelimiterLength := Length(aDelimiter);
if (AnsiRightStr(aOrgList, Length(aDelimiter)) = aDelimiter) then
vRemaingTxt := aOrgList
else
vRemaingTxt := aOrgList + aDelimiter;
aStringList.BeginUpdate;
aStringList.Clear;
try
while Length(vRemaingTxt) > 0 do
begin
vDelimiterPos := Pos(aDelimiter, vRemaingTxt);
vPartialStr := Copy(vRemaingTxt,0,vDelimiterPos-1);
aStringList.Add(vPartialStr);
vRemaingTxt := Copy(vRemaingTxt,vDelimiterPos+vDelimiterLength,MaxInt);
end;
finally
aStringList.EndUpdate;
end;
end;
and it seems to work fine. My problem is syncing the changes in the StringList back to the original String property ? There are so much historical data with this delimiter so I don't think change it to a TChar is a realistic option.
Update:
A clarification. I think I can manage to convert the String to a StringList with the method above. Then display it in the grid should not be so hard. The problem come when I want to convert the TStringList back to the original String property wih '-$-' as delimiter. I cannot do HistoryText := myStringList.Delimitedtext for example.
Second update:
I have solved it. You all got a +1 for fast answers and really trying to help. In summary how I did it.
Read from Historytext:
MyStringList.Text := Historytext;
Now each row have 3 delimiters of '-$-' and each line is separated by a linefeed as usual.
In a loop parse the Stringlist and show it in the grid. I don't bother about MyStringList anymore.
Let the user delete and edit rows in the grid.
When finished loop by row and columns in the grid and build a new string with the same format as original.
Assign that string to HistoryText.
So shift focus from StringList to the grid made it easier :)

Instead of Delimiter (a char) and DelimitedText, you can also use LineBreak (a string) and Text:
lst := TStringList.Create;
try
lst.LineBreak := '-$-';
lst.Text := '16.5.2003-$-12:09-$-anna-$-Organization created';
Memo1.Lines := lst; // or whatever you do with it
finally
lst.Free;
end;
Ans it works even the other way round.

Wild stab in the dark (it isn't very clear what you are asking):
Work through the grid rows:
For each row:
assign an empty string to a temporary string var
For each column add row/column value plus your delimiter to temporary string var
remove last delimiter from temporary string var (if it is non-empty)
add temporary string var to stringlist
Write stringlist's text property back to your HistoryText
const
Delimiter = '-$-';
var
row: Integer;
col: Integer;
SL: TStringList;
rowString: string;
begin
SL := TStringList.Create;
try
for row := 0 to StringGrid1.RowCount - 1 do begin
rowString := '';
for col := 0 to StringGrid1.ColCount - 1 do begin
rowString := StringGrid1.Cells[col, row] + Delimiter;
end;
if rowString <> '' then begin
rowString := Copy(rowString, 1, Length(rowString) - Length(Delimiter));
end;
SL.Add(rowString);
end;
HistoryText := SL.Text;
finally
SL.Free;
end;
end;
Using Uwe's solution of TStrings' LineBreak property:
var
row: Integer;
col: Integer;
SLRows: TStringList;
SLCols: TStringlist;
begin
SLRows := TStringList.Create;
try
SLCols := TStringList.Create;
try
SLCols.LineBreak := '-$-';
for row := 0 to StringGrid1.RowCount - 1 do begin
SLCols.Clear;
for col := 0 to StringGrid1.ColCount - 1 do begin
SLCols.Add(StringGrid1.Cells[col, row]);
end;
SLRows.Add(SLCols.Text);
end;
HistoryText := SLRows.Text;
finally
SLCols.Free;
end;
finally
SLRows.Free;
end;
end;

Related

Stringlist with CommaText is returning comma and spaces instead of just comma in Delphi

I have a string list, each string looks something like this.
2023/01/30,08:47:27, 0. 7.71,CM212-A2,03,Bad head/nozzle detect,380000,Stage No1, Head No2, Nozzle Postion5, Nozzle No0, (Single Lane), PCB ID: , Bad head/nozzle detectReset
I am then adding that string into another list with commatext, and should be giveing a result like so
2023/01/30
08:47:27
0. 7.71
CM212-A2
03
Bad head/nozzle detect
Instead it returns
2023/01/30
08:47:27
0.
7.71
CM212-A2
03
Bad
head/nozzle
detect
It seems it will create a new string for each Comma like I want, but also is creating a new string for each space which I don't want.
Adding Code just incase its needed.
procedure TForm4.Button1Click(Sender: TObject);
var
datalist : tstringlist;
eventlist : tstringlist;
i,x: Integer;
filename : string;
Event : array[1..200] of TEvent;
begin
datalist := tstringlist.Create;
eventlist := tstringlist.Create;
X := 1;
//get latest file
filename := getlastmodifiedfilename('C:\Users\tngmorse\Desktop\LockHeads\Win32\Debug\');
//end
datalist.LoadFromFile(filename);
//search for head lockout
for i := 0 to datalist.count - 1 do
begin
if containstext(datalist[i],'Bad head') then
begin
memo1.Lines.Add(datalist[i]);
// eventlist.Clear;
eventlist.CommaText := datalist[i];
// Event[x].Dateofevent := 'today';
Event[x].Dateofevent := eventlist[0]; //spaces are also breaking it.
Event[x].Timeofevent := eventlist[1];
Event[x].Version := eventlist[2];
Event[x].Machine := Eventlist[3];
Event[x].EventNumber := Eventlist[4];
Event[x].EventName := Eventlist[5];
Event[x].TableNumber := EventList[6];
Event[x].Table := Eventlist[7];
Event[x].Head := Eventlist[8];
Event[x].Nozzle := EventList[9];
Event[x].NozzleType := Eventlist[10];
Event[x].Lane := Eventlist[11];
Event[x].PCBID := Eventlist[12];
Event[x].Effect := Eventlist[13];
memo1.Lines.Add('Date: '+Event[x].Dateofevent);
memo1.Lines.Add('Time: '+Event[x].Timeofevent);
memo1.Lines.Add('Machine: '+Event[x].Machine);
memo1.Lines.Add('Event: '+Event[x].EventName);
memo1.Lines.Add('Table: '+Event[x].Table);
memo1.Lines.Add('Head: '+Event[x].Head);
memo1.Lines.Add('Nozzle: '+Event[x].Nozzle);
memo1.Lines.Add('Status: '+Event[x].Effect);
x:=x+1;
//break down list by comma
//add to record
end;
end;
//end
showmessage('lines: '+inttostr(datalist.Count));
datalist.Destroy;
end;
This behavior can be controlled by the StrictDelimiter property:
If StrictDelimiter is True, individual strings in DelimitedText are only separated by Delimiter or quoted between QuoteChar. If StrictDelimiter is False, spaces and non-printable character are also used as delimiters.
So, set it to True to get the desired behavior.

convert a long string into a Tstringlist

hello guys I have the following string A type string.
A = 'flagA=0,flagB=0,flagC=1'
B:Tstringlist.
I want to convert it into Tstringlist in order to see if the flagC is set to 1 by inspecting B.Values['flagC'].
perhaps i need to split the string under '=' and ',' ?
Any other ideas are welcome thanks.
This should work
B := TStringList.Create;
B.Delimiter := ',';
B.DelimitedText := 'flagA=0,flagB=0,flagC=1';
ShowMessage(B.Values['flagC']);
cars.Free;
enter image description here
you can use that code
procedure TForm1.Button1Click(Sender: TObject);
var
b,a:string;
i:integer;
list:TStringList;
begin
list:=TStringList.Create;
a := 'flagA=0,flagB=0,flagC=1';
for i:=0 to length(a) do
if a[i]='f' then
begin
b := copy(a,i,7);
list.Add(b);
ListBox1.Clear;
ListBox1.Items.Assign(list);
end;
end;
you can use edit1 like this
a:= edit1.text //that consider the contain as string

How to print data of _RecordSet to the text file in delphi 10

how to print all data/records contain in Recordset to the text file in Delphi 10 ?
I could not able to find any Method or property for it.Please guide, i am newbie in delphi.
I have done following:
Var:
CurrField : Field;
RecSet:_RecordSet ;
Begin:
RecSet:= command.Execute(records,Params,-1);
CurrField := RecSet.Fields[0];
end;
but i want to print complete records/data contain in RecSet(_RecordSet type) in text file.
You can write it yourself. If the recordset is relatively small, the easiest way is to use a TStringList.
var
i: Integer;
s: string;
SL: TStringList;
begin
SL := TStringList.Create;
try
while not RecSet.Eof do
begin
// Clear string for the next row
s := '';
// Loop through the fields in this row, creating a comma-separated list
for i := 0 to RecSet.FieldCount - 1 do
s := s + RecSet.Fields[i].Value + ',';
// Remove unnecessary final comma at end
SetLength(s, Length(s) - 1);
// Add to the stringlist
SL.Add(s);
end;
// Save the stringlist content to disk
SL.SaveToFile('YourFileName.txt');
finally
SL.Free;
end;
end;

Incrementing an INI file's section number

I have an INI file that stores some integers for settings. The section names are stored like this:
[ColorScheme_2]
name=Dark Purple Gradient
BackgroundColor=224
BackgroundBottom=2
BackgroundTop=25
...
[ColorScheme_3]
name=Retro
BackgroundColor=5
BackgroundBottom=21
BackgroundTop=8
...
I need to figure out a way to create new sections, that increment the color scheme number +1 from the highest section number. I have a comboBox that lists out the current colorscheme names, so when a user saves to the INI file, the existing scheme is just overwritten. How can I check the ComboBox text to see if it is an existing section and if not, create a new one with an incremented name? (i.e. from the example code above, ColorScheme_2 and ColorScheme_3 already exist, so the next section to create would be ColorScheme_4).
You can read all sections by using ReadSections method, then iterate returned string list and parse each item in it to store the highest found index value:
uses
IniFiles;
function GetMaxSectionIndex(const AFileName: string): Integer;
var
S: string;
I: Integer;
Index: Integer;
IniFile: TIniFile;
Sections: TStringList;
const
ColorScheme = 'ColorScheme_';
begin
Result := 0;
IniFile := TIniFile.Create(AFileName);
try
Sections := TStringList.Create;
try
IniFile.ReadSections(Sections);
for I := 0 to Sections.Count - 1 do
begin
S := Sections[I];
if Pos(ColorScheme, S) = 1 then
begin
Delete(S, 1, Length(ColorScheme));
if TryStrToInt(S, Index) then
if Index > Result then
Result := Index;
end;
end;
finally
Sections.Free;
end;
finally
IniFile.Free;
end;
end;
And the usage:
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(IntToStr(GetMaxSectionIndex('d:\Config.ini')));
end;
How can I check the ComboBox text to see if it is an existing section and if not, create a new one with an incremented name?
Like this:
const
cPrefix = 'ColorScheme_';
var
Ini: TIniFile;
Sections: TStringList;
SectionName: String;
I, Number, MaxNumber: Integer;
begin
Ini := TIniFile.Create('myfile.ini')
try
SectionName := ComboBox1.Text;
Sections := TStringList.Create;
try
Ini.ReadSections(Sections);
Sections.CaseSensitive := False;
if Sections.IndexOf(SectionName) = -1 then
begin
MaxNumber := 0;
for I := 0 to Sections.Count-1 do
begin
if StartsText(cPrefix, Sections[I]) then
begin
if TryStrToInt(Copy(Sections[I], Length(cPrefix)+1, MaxInt), Number) then
begin
if Number > MaxNumber then
MaxNumber := Number;
end;
end;
end;
SectionName := Format('%s%d', [cPrefix, MaxNumber+1]);
end;
finally
Sections.Free;
end;
// use SectionName as needed...
finally
Ini.Free;
end;
end;

How to get selected cell text from TcxGrid?

I'm using Devexpress TcxGrid and I'm trying to get selected cell text. My TcxGrid is connected to some kind of DataSource - I think it is DataControler.
My goal is to get the text from cells in the entire row and place it in string divided with comas.
If you want values with multiselection and from a TcxGridDbTableView:
In my result i don't have a separation between rows.
function GetSelectedValuesFrmGrid: String;
var
intSelectLoop,
intRowLoop: Integer;
oTableView: TcxGridDbTableView;
strValue: Variant;
oList: TStringList;
begin
Result:= '';
// Kind Of TableView
if <TcxGrid>.ActiveView is TcxGridDbTableView then
begin
oTableView:= <TcxGrid>.ActiveView as TcxGridDbTableView;
oList:= TStringList.Create();
try
for intSelectLoop:= 0 to oTableView.Controller.SelectedRowCount-1 do
begin
for intRowLoop:= 0 to oTableView.Controller.SelectedRows[intSelectLoop].ValueCount-1 do
begin
strValue:= oTableView.Controller.SelectedRows[intSelectLoop].Values[intRowLoop];
// Value can be Null
if VarIsNull(strValue) then
begin
strValue:= '';
end;
oList.Add(strValue);
end;
end;
Result:= oList.CommaText;
finally
oList.Free;
end;
end;
end;
You need the text from all cells in selected rows?
for I := 0 to cxGridDBTableView.Controller.SelectedRowCount -1 do
for J := 0 to cxGridDBTableView.Controller.SelectedRows[I].ValueCount -1 do
SelectedRowStr := SelectedRowStr + VarToStr(cxGrid1DBTableView1.Controller.SelectedRows[I].Values[J]) + ',';
SelectedRowStr := Copy(SelectedRowStr,1,length(SelectedRowStr)-1);
The grid will have a DataControler descendant. You can cycle through the items in the DataController and, depending on how your grid is configured, the items in the DataController can correspond to individual 'columns' shown in your grid. That being said the items in a DataController stay in ther
This code will let you cycle through each column in the grid and build up the string based on the DataController values.
var
i: Integer;
DC: TcxCustomDataController;
s: string;
begin
s := '';
DC := <yourgrid>.DataController;
for i := 0 to <yourgrid>.ColumnCount -1 do begin
s := s + vartostr(DC.Values[DC.FocusedRecordIndex, <yourgrid>.Columns[i].Index]) + ',';
end;
if Length(s) > 0 then
s := Copy(s,1,Length(s)-1);
end;

Resources