Delphi: как динамически разбить строку на подстроки в соответствии с (динамической) маской

Это моя ситуация: у меня есть текстовый файл, содержащий множество строк одинаковой длины, представляющих записи, которые нужно загрузить в таблицу базы данных SQL, поэтому мне придется сгенерировать код SQL из этих строк.
У меня есть таблица в этой БД (назовем ее «таблицей форматирования»), которая сообщает мне, как форматируются строки и где их загружать (каждая запись этой таблицы содержит имя целевой таблицы, имя поля, положение данных и длину, относящуюся к строкам из текстовый файл).

Я уже решил эту проблему способом, который, как мне кажется, хорошо известен каждому программисту Delphi, используя функцию Copy(string, pos, length) и перебирая каждое поле, основываясь на информации из «таблицы форматирования».
Это хорошо работает, но это медленно, особенно когда мы говорим об исходных текстовых файлах с миллионом или более строк, каждая из которых представляет несколько десятков или даже сотен полей данных.

Сейчас я пытаюсь «увидеть» исходные строки таким образом, чтобы они казались уже разделенными, избегая функции Copy(), которая постоянно создает новые строки, копируя содержимое исходной строки, выделяя и освобождая память и так далее. Я бы сказал: «У меня есть вся строка, давайте посмотрим на нее так, чтобы она представляла каждую« часть »(поле) за один шаг, без создания из нее подстрок».

Что могло бы решить мою проблему, так это способ определить динамическую структуру, такую ​​как динамическая запись или динамический массив (не то, что Delphy называет динамическим массивом, больше чем-то вроде «динамического статического массива»), чтобы «наложить» на строку по порядку чтобы "наблюдать" это с этой точки зрения ... Я не знаю, что достаточно ясно понимаю это объяснение ... Однако Delphi (насколько мне известно) не реализует такого рода динамические структуры.

Это кусок (статического) кода, который делает то, что я хочу, за исключением отсутствия динамизма.

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;

Есть идеи, как решить эту проблему?

Заранее спасибо.


person Bozzy    schedule 08.04.2011    source источник


Ответы (2)


Вы действительно не можете избежать создания лишних строк. Ваш пример в конце вашего вопроса создает строки.

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

Ваш вызов TStrings.Add() в этом коде создает динамическую строку неявно из переданного вами параметра, а затем эта строка передается в Add().

Решение с Copy, вероятно, является правильным, поскольку я не вижу простого способа избежать копирования памяти, если вы хотите что-либо сделать с разделенными строками.

person David Heffernan    schedule 08.04.2011
comment
вы говорите мне, что PDecodeStr(PAnsiString(cWholeStr)).s1 фактически создает копию исходной строки? Разве это не вид этой строки, ограниченный конструкцией Array[0..x] of AnsiChar? - person Bozzy; 08.04.2011
comment
@Bozzy Не совсем. Если бы вы работали с переменной PDecodeStr и написали, скажем, PDecodeStr(..)[1] := '?', то копирования не было бы. Но я уверен, что вы захотите передать свой PDecodeStr функциям для сравнения, добавления в списки и т. Д. И это повлечет за собой копию. - person David Heffernan; 08.04.2011
comment
Боззи: используйте окна отладки - ›CPU и убедитесь сами. - person Marco van de Voort; 08.04.2011

Я думаю, что в Delphi нет более эффективного способа, чем использование Copy.

Но другое решение - загрузить все строки непосредственно во временную таблицу с одним столбцом, а затем выполнить заполнение с помощью SQL-запроса. Общее время зависит от множества параметров, поэтому лучше всего проверить !!

person philnext    schedule 08.04.2011
comment
Это может быть хорошим решением для импорта данных общего назначения из текста, но в моей конкретной ситуации мне также нужно учесть некоторые соображения, которые было бы слишком сложно или почти невозможно реализовать с помощью чистого SQL. Однако спасибо за альтернативное решение. - person Bozzy; 08.04.2011
comment
Хорошо, но вы можете сохранить эти соображения (фильтры?) Для кода и разрешить разделение только на сервер базы данных. - person philnext; 08.04.2011