Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi: how to dynamically "split" a string into substrings according to a (dynamic) mask

This is my situation: I have a text file containing a lot of equal-length strings representing records to be loaded into an SQL DB table, so I'll have to generate SQL code from these strings.
I than have a table on that DB (let's call it the "formatting table") that tells me how the strings are formatted and where to load them (each record of that table contains the destination table name, field name, data position and length referred to the strings from the text file).

I have already solved that problem in a way I think it's well-known to every Delphi programmer, using the Copy(string, pos, length) function and iterating through each field, based on the informations from the "formatting table".
That works well, but it's slow, especially when we talk of source text files with a million or more of lines, each representing several tens or even hundreds of data fields.

What I'm trying to do now is to "see" the source strings in a way that they appear already splitted, avoiding the Copy() funcion that continuously create new strings copying the content from the original string, allocating and freeing memory and so on. What I'd say is "I have the whole string, let's see it in a way that represent each 'piece' (field) of it in a single step, without creating substrings from it".

What could solve my problem would be some way to define a dynamic structure like a dynamic record or a dynamic array (not what Delphy calls a dynamic array, more something like a "dynamic static array") to "superimpose" on the string in order to "watch" it from that point of view... I don't know I'm sufficiently clear on that explanation... However Delphi (from my knowledge) doesn't implements such kind of dynamic structures.

This is a piece of (static) code that does what I want, apart from the lack of dynamism.

procedure TForm1.FormCreate(Sender: TObject);
type
  PDecodeStr = ^TDecodeStr;
  TDecodeStr = record
    s1: Array[0..3] of AnsiChar;
    s2: Array[0..9] of AnsiChar;
    s3: Array[0..4] of AnsiChar;
    s4: Array[0..7] of AnsiChar;
    s5: Array[0..2] of AnsiChar;
  end;
var
  cWholeStr: AnsiString;
begin
  cWholeStr := '123456789012345678901234567890';
  Memo1.Lines.Add(PDecodeStr(PAnsiString(cWholeStr)).s1);
  Memo1.Lines.Add(PDecodeStr(PAnsiString(cWholeStr)).s2);
  Memo1.Lines.Add(PDecodeStr(PAnsiString(cWholeStr)).s3);
  Memo1.Lines.Add(PDecodeStr(PAnsiString(cWholeStr)).s4);
  Memo1.Lines.Add(PDecodeStr(PAnsiString(cWholeStr)).s5);
end;

Any idea on how to solve this problem?

Thanks in advance.

like image 435
Bozzy Avatar asked Nov 21 '25 22:11

Bozzy


1 Answers

You can't really avoid creating extra strings. Your example at the end of your question creates strings.

Memo1.Lines.Add(PDecodeStr(PAnsiString(cWholeStr)).s1)

Your call to TStrings.Add() in this code creates a dynamic string implicitly from the parameter you pass and then this string is passed to Add().

The solution with Copy is probably the way to go since I don't see any easy way to avoid the copying of memory if you wish to do anything with the split strings.

like image 152
David Heffernan Avatar answered Nov 23 '25 11:11

David Heffernan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!