Okay I am still very new to delphi coding and coding in general. I have researched on splitting strings into an array or list delimited by : or , but in this case I need to do it by a string that is delimited by " ".
Example: "fname","lastname","someplace,state","some business,llc","companyid"
and what I need is the array to be
(item[0] = fname) (item[1] = lastname) (item [2] = someplace,state) (item[3] = some business, llc.) (item[4] = companyid)
So as you can see I cannot read in a line of text using the comma as a delimeter because it would throw everything off.
Is there any way to read in a line of text and split it into an array like the example above??
See documentation for TStrings.CommaText.
Here is an example:
program Project1;
{$APPTYPE CONSOLE}
uses
System.SysUtils,Classes;
var sl: TStringList;
s: String;
begin
sl := TStringList.Create;
try
sl.CommaText := '"fname","lastname","someplace,state","some business,llc","companyid"';
for s in sl do
WriteLn(s);
ReadLn;
finally
sl.Free;
end;
end.
The documentation also says:
Note: CommaText is the same as the DelimitedText property with a delimiter of ',' and a quote character of '"'.
So if using DelimitedText, just make sure QuoteChar is " and the Delimiter is ,.
Related
Currently I have something like but I'm unable to retrieve my data from the dataset when it has single quote in the data
procedure TForm1.AfterConstruction;
begin
inherited;
cdsMain.FieldDefs.Add('ItemCode', ftWideString, 20);
cdsMain.CreateDataSet;
cdsDetail.FieldDefs.Add('ItemCode', ftWideString, 20);
cdsDetail.FieldDefs.Add('Project', ftWideString, 20);
cdsDetail.CreateDataSet;
var S := '6x8''''';
cdsMain.AppendRecord([S]);
cdsDetail.AppendRecord([S, 'P01']);
cdsDetail.AppendRecord([S, 'P02']);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if FDConnection1.Connected then
FDConnection1.Close;
if FDLocalSQL1.Active then
FDLocalSQL1.Active := False;
FDLocalSQL1.Active := True;
FDQuery1.Open('SELECT A.ItemCode, B.Project FROM Main A INNER JOIN Detail B ON (A.ItemCode=B.ItemCode)');
end;
My expected result are
ItemCode Project
6x8' P01
6x8' P02
The error I get when I use var S := '6x8''''
Source code
From what I can deduce from the source files, there's a bug in FireDAC in this case. If I eliminate the ON clause in the SQL, it works, even with an ASCII Single-Quote (#39). If I replace the ASCII Single-Quote (#39) with the UNICODE Single-Quote (#8216) or remove it altogether, it works.
It seems like the parser for TFDLocalSQL (I think) has a bug when it tries to resolve the ON clause and there's an ASCII Single-Quote involved.
You should report the error to Embarcadero at https://quality.embarcadero.com, including your source code and an explanation.
I am trying to write a program to read a long list of book(1000 books),isbn etc
but when the program runs, it shows range overrun
the format of txt is
1
1234567890
ABC book
peter
20
2
1234567896
...
the code is:
const maxbk=1000;
type bookrecord = record
book_no:string;
isbn:string;
book_name:string;
author:string;
borrowed:string;
end;
var booklist : array[1..maxbk] of bookrecord;totalbook:integer;
procedure readbooklist(var bklist:array of bookrecord;var totalbk:integer);
var f:text;temp:string;code:integer;
begin
totalbk:=0;
assign(f,'bklist.txt');
reset(f);
while not eof(f) do
begin
readln(f,bklist[totalbk+1].book_no);
readln(f,bklist[totalbk+1].isbn);
readln(f,bklist[totalbk+1].book_name);
readln(f,bklist[totalbk+1].author);
readln(f,bklist[totalbk+1].borrowed);
totalbk:=totalbk+1;
end;
close(f);
writeln('read file done');
end;
begin
readbooklist(booklist,totalbook);
end.
who can help to fix the problem??
I think the problem is in your handling of the array parameter. Try this (highlighted in bold are the changes I've added):
const maxbk=1000;
type bookrecord = record
book_no:string;
isbn:string;
book_name:string;
author:string;
borrowed:string;
end;
var booklist : array[1..maxbk] of bookrecord; totalbook:integer;
procedure readbooklist(var bklist:array of bookrecord;var totalbk:integer);
var f:text;temp:string;code:integer;
begin
totalbk:=Low(bklist);
assign(f,'bklist.txt');
reset(f);
while not eof(f) do
begin
readln(f,bklist[totalbk].book_no);
readln(f,bklist[totalbk].isbn);
readln(f,bklist[totalbk].book_name);
readln(f,bklist[totalbk].author);
readln(f,bklist[totalbk].borrowed);
totalbk:=totalbk+1;
end;
totalbk := totalbk - Low(bklist);
close(f);
writeln('read file done');
end;
begin
readbooklist(booklist,totalbook);
end.
Also, a few choice spaces would help with readability (like a space after each comma and around assignment operators).
Note, too, that your code (and the changed code I'm providing) don't check for incomplete records in your input text file or properly check for blank lines, etc (e.g., invalid book_no values). You should attempt to add some code which makes it a little more resilient to problems in the input file. As others have pointed out, there are probably better ways to structure the input and read it as well.
I have a procedure that I found from another question that supposedly splits/delimits a string , when provided a string, a delimiter, and and a TStrings list. That procedure is:
procedure SplitString(const Delimiter: Char; Input: string; const Strings: TStrings);
begin
//Delimits or splits the received string, returns TStrings array
Assert(Assigned(Strings)) ;
Strings.Clear;
Strings.Delimiter := Delimiter;
Strings.DelimitedText := Input;
end;
However when I provided it this:
SplitString('=',test,EqualParse);
Where test is a string 200 : NCPATH -------------> = C:\SNDATA\NC\ and EqualParse is a TStringList, all that I get back is 200 for EqualParse[0] (which should be everything to the left of the equal sign. I am expecting to get back 200 : NCPATH ------------->. Is there something wrong with how I am using that code? Can I modify is to also not split by a space if not explicitly done?
You need to set TStrings.StrictDelimiter to True, otherwise DelimitedText includes whitespace as a delimiter.
procedure SplitString(const Delimiter: Char; Input: string; const Strings: TStrings);
begin
//Delimits or splits the received string, returns TStrings array
Assert(Assigned(Strings)) ;
Strings.Clear;
Strings.Delimiter := Delimiter;
Strings.StrictDelimiter := True; // <-- add this
Strings.DelimitedText := Input;
end;
This is documented behavior:
If StrictDelimiter is set to False, the space character is also interpreted as a delimiter, regardless of the value of Delimiter.
With that said, setting the delimiter properties of the input TStrings may have unwanted side effects on the caller, so I would suggest using a local TStringList for the parsing:
procedure SplitString(const Delimiter: Char; Input: string; const Strings: TStrings);
var
Tmp: TStringList;
begin
Assert(Assigned(Strings)) ;
tmp := TStringList.Create;
try
tmp.Delimiter := Delimiter;
tmp.StrictDelimiter := True;
tmp.DelimitedText := Input;
Strings.Assign(tmp);
finally
tmp.Free;
end;
end;
I need to go through a ton of data that is stored in a paradox table within a Memo field. I need to process this data line by line and process each line.
How can I tell Delphi to fetch each line in the memo field one by one?
Could I use #13#10 as a delimiter?
Assuming that what is in the memo field uses #13#10 as the line separator then I would use a TStringList, and the very useful Text property to split the memo field text into separate lines:
var
StringList: TStringList;
Line: string;
.....
StringList.Text := MemoFieldText;
for Line in StringList do
Process(Line);
Even if your memo field uses Unix linefeeds then this code will interpret the memo field correctly.
It depends on how the field is actually declared in Paradox. If it's a TMemoField, it's pretty easy:
var
SL: TStringList;
Line: string;
begin
SL := TStringList.Create;
try
SL.Text := YourMemoField.GetAsString;
for Line in SL do
// Process each line of text using `Line`
finally
SL.Free;
end;
end;
If it's a TBlobField, it's a little more complicated. You need to read the memo field using a TBlobStream, and load the content of that stream into a TStringList:
// For Delphi versions that support it:
procedure LoadBlobToStringList(const DS: TDataSet; const FieldName: string;
const SL: TStringList);
var
Stream: TStream;
begin
Assert(Assigned(SL), 'Create the stringlist for LoadBlobToStringList!');
SL.Clear;
Stream := DS.CreateBlobStream(DS.FieldByName(FieldName), bmRead);
try
SL.LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
// For older Delphi versions that do not have TDataSet.CreateBlobStream
procedure LoadBlobToStringList(const DS: TDataSet; const TheField: TField;
const SL: TStringList);
var
BlobStr: TBlobStream;
begin
Assert(Assigned(SL), 'Create the stringlist for LoadBlobToStringList!');
SL.Clear;
BlobStr := TBlobStream.Create(DS.FieldByName(TheField), bmRead);
try
SL.LoadFromStream(BlobStr);
finally
BlobStr.Free;
end;
end;
// Use it
var
SL: TStringList;
Line: string;
begin
SL := TStringList.Create;
LoadBlobToStringList(YourTable, YourMemoFieldName, SL);
for Line in SL do
// Process each Line, which will be the individual line in the blob field
// Alternatively, for earlier Delphi versions that don't support for..in
// declare an integer variable `i`
for i := 0 to SL.Count - 1 do
begin
Line := SL[i];
// process line of text using Line
end;
end;
I have a Base64 encoded String that contains PDF data. Using the EncdDecd unit I can decode the String to a Byte Array.
This is where I am having trouble: I tried saving the characters to a String but once it hits a zero value (ASCII = 0 or #0 or $00) the String no longer appends. Example:
uses
EncdDecd;
var
EncodedString : String;
Report : String;
Base64Bytes: TBytes; // contains the binary data
begin
Base64Bytes := DecodeBase64(EncodedString);
for I := 0 to Length(Base64Bytes) - 1 do
begin
Report := Report + Chr(Base64Bytes[I]);
end;
Writing to a text file seems to work better but after renaming it to .PDF the file does not open correctly.
How can I write to a binary file in Delphi? Or even save the data to a stream? Basically I am just trying to take the encoded String and save it to a PDF/binary file, or display the PDF in Delphi.
I have looked around quite a bit and found a possible solution in
Saving a Base64 string to disk as a binary using Delphi 2007 but is there another way?
This should do it:
procedure DecodeBaseToFile(const FileName: string;
const EncodedString: AnsiString);
var
bytes: TBytes;
Stream: TFileStream;
begin
bytes := DecodeBase64(EncodedString);
Stream := TFileStream.Create(FileName, fmCreate);
try
if bytes<>nil then
Stream.WriteBuffer(bytes[0], Length(bytes));
finally
Stream.Free;
end;
end;
Note: I have only compiled this in my head.