I have a Tstringlist containing a list of keys used in a database table.
I'd like a simple way to generate one string containing all the keys, with each separated by a comma and enclosed in single quotes.
This is so that it can be used in a SQL 'IN' statement
eg WHERE FieldX IN ('One','Two','Three').
I've tried using quotechar but it is ignored when reading the commatext.
eg the following code
procedure junk;
var
SL : Tstringlist;
s : string;
begin
SL := Tstringlist.Create;
SL.Delimiter :=','; //comma delimiter
SL.QuoteChar := ''''; //single quote around strings
SL.Add('One');
SL.Add('Two');
SL.Add('Three');
try
s := SL.commatext;
showmessage(s);
finally
SL.Free;
end; //finally
end; //junk
shows the message One,Two,Three - without any quotes.
I know I can do it the long way round, as in
procedure junk;
var
SL : Tstringlist;
s : string;
i : integer;
begin
SL := Tstringlist.Create;
SL.Delimiter :=','; //comma delimiter
SL.Add('One');
SL.Add('Two');
SL.Add('Three');
try
s := '';
for I := 0 to SL.Count - 1 do
begin
s := s + ',' + '''' + SL[i] + '''';
end;
delete(s,1,1);
showmessage(s);
finally
SL.Free;
end;//finally
end;
but is there a simpler way using properties of the Tstringlist itself?
If you're using D2006 or later, you can use a CLASS HELPER:
USES Classes,StrUtils;
TYPE
TStringListHelper = CLASS HELPER FOR TStrings
FUNCTION ToSQL : STRING;
END;
FUNCTION TStringListHelper.ToSQL : STRING;
VAR
S : STRING;
FUNCTION QuotedStr(CONST S : STRING) : STRING;
BEGIN
Result:=''''+ReplaceStr(S,'''','''''')+''''
END;
BEGIN
Result:='';
FOR S IN Self DO BEGIN
IF Result='' THEN Result:='(' ELSE Result:=Result+',';
Result:=Result+QuotedStr(S)
END;
IF Result<>'' THEN Result:=Result+')'
END;
This code:
SL:=TStringList.Create;
SL.Add('One');
SL.Add('Two');
SL.Add('Number Three');
SL.Add('It''s number 4');
WRITELN('SELECT * FROM TABLE WHERE FIELD IN '+SL.ToSQL);
will then output:
SELECT * FROM TABLE WHERE FIELD IN ('One','Two','Number Three','It''s number 4')
Use sl.DelimitedText instead of sl.CommaText to make it follow your settings. CommaText will temporarily change the Delimiter and QuoteChar to some hardcoded values.
CommaText (and apparently also DelimitedText) can not be relied on to add the quotes, because they treat single word and multi word strings differently.
When retrieving CommaText, any string in the list that include spaces,
commas or quotes will be contained in double quotes, and any double
quotes in a string will be repeated.
There doesn't seem to be any combination with the TStringList alone, so I suggest you add the strings using QuotedStr.
Following settings work as you wish, regardless of, whether strings are single words or multi words:
SL := Tstringlist.Create;
SL.Delimiter :=','; //comma delimiter
SL.StrictDelimiter := True;
// SL.QuoteChar := ''''; //single quote around strings
// SL.Add('One');
// SL.Add('Two words');
// SL.Add('Three');
SL.Add(QuotedStr('One'));
SL.Add(QuotedStr('Two words'));
SL.Add(QuotedStr('Three'));
s := SL.CommaText; // or SL.DelimitedText;
showmessage(s);
Output is:
'One','Two words','Three'
The TStrings.DelimitedText methods quote only the strings when needed: when there's something link O'ne this will print as 'O''ne' - i.e. it double the quotes.
You can achieve what you want setting a convenience delimiter and the QuoteChar property to the #0 value and then replacing the delimiters with the quotes.
procedure junk;
var
sl : Tstringlist;
s: string;
begin
sl := Tstringlist.Create;
try
sl.Delimiter := '|';
sl.QuoteChar := #0;//no quote
sl.Add('On''e');
sl.Add('Two');
sl.Add('Three');
//escape the single quotes
s := StringReplace(sl.DelimitedText, '''', '''''', [rfReplaceAll]);
//replace the delimiters and quote the text
s := '''' + StringReplace(s, sl.Delimiter, ''',''', [rfReplaceAll]) + '''';
WriteLn(s);
finally
sl.Free;
end;
end;
I have resolved a similar issue with something like that :
s := ''' + StringReplace(sl.CommaText, ',', ''',''', [rfReplaceAll]) + '''
Related
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 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;
I am executing a sql-statement on a oracle database and writing the results into a textfile. A field, called "targets" (varchar2) has line breaks in it.
Until now i replaced the line breaks like this:
function CleanText(strText : String) : String;
var
ii: integer;
begin
for ii := 1 to Length(strText) do
if strText[ii] < chr(32) then strText[ii] := ' ';
end;
Result := strText;
end;
But now i want to replace the line breaks with a specific string: "{\n}". I tried different things like:
strText := AnsiReplaceStr(strText, #13#10, '{\n}');
But it doesnt work. There a no "{\n}" in the written textfile.
I copy pasted an example string out of the sql-statement:
"1) Sicherung der Liquidität der Stadt XYZ durch:'#$A'- exakte Buchführung zur Sicherung des korrekten Ausweises der Forderungen / Verbindlichkeiten"
I could do something like this (but i think, that's not a good solution):
strText := AnsiReplaceStr(strText, '''#$A''', '{\n}');
Do you have any ideas?
Regards,
Dennis
Use SysUtils.AdjustLineBreaks first to normalize line breaks:
strText := AdjustLineBreaks(strText, tlbsCRLF);
strText := AnsiReplaceStr(strText, #13#10, '{\n}');
Another option is to use a TStringList with its LineBreak property:
function CleanText(strText : String) : String;
var
sl: TStringList;
begin
sl := TStringList.Create;
try
sl.Text := strText;
sl.LineBreak := '{\n}';
Result := sl.Text;
finally
sl.Free;
end;
end;
I have string 'AAA'+#$0d+#$0a+'BBB'+#$01d+'CCC'. I need to split according #$1d character like:
'AAA'+#$0d+#$0a+'BBB'
'CCC'
I'm using function:
procedure Split(Delimiter: Char; Str: string; ListOfStrings: TStrings) ;
begin
ListOfStrings.Clear;
ListOfStrings.Delimiter := Delimiter;
ListOfStrings.DelimitedText := Str;
ListOfStrings.StrictDelimiter:= true;
end;
...
split(#$1d,'AAA'+#$0d+#$0a+'BBB'+#$01d+'CCC',sl);
Unfortunately it splits also according CRLF that I don't need.
How to have strings spited just by #$1d?
You have to set ListOfStrings.StrictDelimiter:= true; before setting the of the property DelimitedText.
ListOfStrings.StrictDelimiter:= true;
ListOfStrings.DelimitedText := Str;
I want to add 30 different strings into a stringList . I do not want to add AList.Items.Add 30 times. Nor do i want to keep the strings in an array and run a loop. I was thinking may be i could write a single AList.Add ( not in a loop) where the strings to be added were seperated by a Delimiter .
e.g.
AList.Add('Data1' + <Delim> + 'Data2' ...)
How to do that ?
Please note that i am just curious as to if it can be done this way. It is quite ok if not as there are better ways to accomplish this. ( keeping the strings in an array and using a loop to add data is my idea)
Thanks in Advance
You can write a procedure that does this:
procedure SLAddStrings(SL: TStrings; S: array of string);
var
i: Integer;
begin
SL.BeginUpdate;
for i := low(S) to high(S) do
SL.Add(S[i]);
SL.EndUpdate;
end;
Try it:
var
SL: TStringList;
begin
SL := TStringList.Create;
SLAddStrings(SL, ['car', 'cat', 'dog']);
Create a temporary TStringList, assign the string to its DelimitedText property, pass the temporary to the AddStrings() method of the destination TStringList, and then free the temporary.
var
Temp: TStringList;
begin
Temp := TStringList.Create;
try
Temp.Delimiter := <Delim>;
// if using a Delphi version that has StrictDelimiter available:
// Temp.StrictDelimiter := True;
Temp.DelimitedText := 'Data1' + <Delim> + 'Data2' ...;
AList.AddStrings(Temp);
finally
Temp.Free;
end;
end;
Just use DelimitedText property. E.g. if your delimiter is set to , (default in TStringList) then you can write this code:
AList.DelimitedText := 'Data1,Data2';
you can use TStringList.DelimitedText property to add text, wich uses your Delimiter char. TStringList will split your text and then you can access each string separately using strings property;
program Project3;
{$APPTYPE CONSOLE}
uses classes;
const DATA = 'one,two,three';
var sl : TStringList;
s : string;
begin
sl := TStringList.Create();
try
sl.Delimiter := ',';
sl.DelimitedText := DATA;
for s in sl do begin
writeln(s);
end;
readln;
finally
sl.Free();
end;
end.
and result is
one
two
three