Как я могу перебрать строку с разделителями и присвоить содержимое строки локальным переменным Delphi?

Я написал функцию Delphi, которая загружает данные из файла .dat в список строк. Затем он декодирует список строк и присваивает значение строковой переменной. Содержимое строки использует символ «#» в качестве разделителя.

Как я могу затем взять содержимое этой строки, а затем присвоить его содержимое локальным переменным?

// Function loads data from a dat file and assigns to a String List.
function TfrmMain.LoadFromFile;
var 
  index, Count : integer;
  profileFile, DecodedString : string;
begin
  // Open a file and assign to a local variable.
  OpenDialog1.Execute;
  profileFile := OpenDialog1.FileName;
  if profileFile = '' then
    exit;
  profileList := TStringList.Create;
  profileList.LoadFromFile(profileFile);
  for index := 0 to profileList.Count - 1 do
  begin
    Line := '';
    Line := profileList[Index];
  end;
end;

После декодирования var "Line" содержит что-то вроде этого:

пример:

Line '23#80#10#2#1#...255#'.

Не все значения между разделителями имеют одинаковую длину, и значение «Line» будет меняться каждый раз, когда вызывается функция LoadFromFile (например, иногда значение может иметь только одно число в следующих двух или трех и т. д., поэтому я не могу полагаться на Функция копирования для строк или массивов).

Я пытаюсь найти способ перебора содержимого «Линии», назначая его локальной переменной с именем «буфер», а затем, если он встречает «#», он затем присваивает значение буфера локальной переменной, повторно инициализирует буфер в ''; а затем переходит к следующему значению в «Строке», повторяя процесс для следующего параметра, каждый раз игнорируя «#».

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

Огромное спасибо

KD


person kvnDalley    schedule 14.08.2012    source источник
comment
Является ли файл одной строкой или несколькими строками с разделителями #?   -  person Arioch 'The    schedule 14.08.2012
comment
похоже у вас не бесплатный profileList. Это утечка памяти. Если вам нужно разбить файл на строки перед разбором каждой строки, вам следует использовать try-finally, чтобы освободить объект. Посмотрите на ответ @UweRaabe - и используйте тот же шаблон создания и освобождения profileList. Список профилей корпуса предполагает, что вы пришли из страны Явы или что-то в этом роде. Здесь нет сборки мусора, это Delphi. Если вы что-то создали - вы обязаны это освободить. Однако есть интерфейсы с подсчетом ссылок, такие как IJclStringList, упомянутый в моем ответе. Они будут освобождены компилятором.   -  person Arioch 'The    schedule 14.08.2012
comment
Если в файле не несколько строк, а одна, то читать ее следует в строковую переменную, а не в список строк.   -  person Arioch 'The    schedule 14.08.2012
comment
OpenDialog1.Выполнить; - не могли бы вы проверить результат? если пользователь нажмет кнопку отмены, он будет очень удивлен результатом...   -  person Arioch 'The    schedule 14.08.2012
comment
@Arioch'The, тем больше я чувствую, что вам нужна специальная вкладка для ваших комментариев здесь, в StackOverflow. Тогда люди могли просто прочитать вопрос с комментариями других и при желании переключиться на вкладку с вашими :-)   -  person TLama    schedule 14.08.2012
comment
@Arioch'The: Пожалуйста, не поддавайтесь желанию прокомментировать каждый вопрос несколько раз. Вы добавляете к ним ненужный шум и беспорядок. Не всем нужны ваши советы и консультации по каждому посту. Это не чат или дискуссионная группа; FAQ содержит информацию о том, как должны использоваться комментарии. Спасибо. :-)   -  person Ken White    schedule 14.08.2012
comment
Ну, если бы в комментариях был какой-то разделитель текста... но его нет. Новые строки проглатываются. Если хотите поболтать в комментариях - то ладно. Но если вы хотите структурировать информацию в комментарии - нет возможности. Это не говоря об ограничении в 455 символов.   -  person Arioch 'The    schedule 15.08.2012


Ответы (4)


Вам нужен второй TStringList:

  lineLst := TStringList.Create;
  try
    lineLst.Delimiter := '#';
    lineLst.DelimitedText := Line;
    ...
  finally
    lineLst.Free;
  end;

В зависимости от вашей версии Delphi вы можете установить lineLst.StrictDelimiter := true, если строка содержит пробелы.

person Uwe Raabe    schedule 14.08.2012
comment
В зависимости от вашей версии Delphi - вот что я ненавижу в этом подходе. Просто эмоционально не нравится :-) - person Arioch 'The; 14.08.2012
comment
Спасибо за ответ - я должен был сказать, что версия была XE2. - person kvnDalley; 14.08.2012
comment
@Arioch'The, версия Delphi имеет значение только тогда, когда вам нужен StrictDelimiter, что необходимо только в том случае, если в строковых данных есть пробелы. Без этого пробелы также рассматриваются как разделители. - person Uwe Raabe; 14.08.2012

Вы можете сделать что-то вроде этого:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, StrUtils;

var
  S : string;
  D : string;

begin
  S := '23#80#10#2#1#...255#';

  for D in SplitString(S,'#') do //SplitString is in the StrUtils unit
    writeln(D);

  readln;
end.
person Svein Bringsli    schedule 14.08.2012

Вы не указали свою версию Delphi, поэтому я не знаю, применима она или нет. Это зависит от версии IS. Пожалуйста, сделай!

В порядке моих личных предпочтений:

1: Загрузите Jedi CodeLib — http://jcl.sf.net. Затем используйте TJclStringList. У него очень хороший сплит-метод. После этого вам нужно будет только повторить.

функция Split(const AText, ASeparator: string; AClearBeforeAdd: Boolean = True): IJclStringList;

uses JclStringLists;
...
var s: string;  js: IJclStringList.
begin
...
   js := TJclStringList.Create().Split(input, '#', True);
   for s in js do begin
      .....
   end;
...
end;

2: Delphi теперь имеет несколько менее многофункциональную процедуру StringSplit. http://docwiki.embarcadero.com/Libraries/en/System.StrUtils.SplitString Недостаток в том, что тип массив строк может быть несовместим с самим собой по присваиванию. Здравствуй, правила Паскаля 1949...

uses StrUtils;
...
var s: string;  
    a_s: TStringDynArray; 
(* aka array-of-string aka TArray<string>. But you have to remember this term exactly*)
begin
...
   a_s := SplitString(input, '#');
   for s in a_s do begin
      .....
   end;
...
end;

3: Используйте TStringList. Основная проблема с ним заключается в том, что он был разработан таким образом, что пробелы или новые строки являются встроенными разделителями. В новых Delphi это можно подавить. В целом код должен быть адаптирован к вашей точной версии Delphi. Вы можете легко найти в Google что-то вроде «Использование TStringlist для разделения строки» и получить множество примеров (например, @Uwe).

Но вы можете забыть подавить здесь или там. А можно и на стареньких Дельфах, где этого сделать нельзя. И вы можете неправильно применить пример для другой версии Delphi. И... это просто скучно :-) Хотя вы можете сделать свою собственную функцию для генерации таких предварительно настроенных списков строк для вас и тщательно проверять в ней версию Delphi :-) Но тогда вам придется тщательно освобождать этот объект после использования.

person Arioch 'The    schedule 14.08.2012
comment
Извините, я должен был сказать Delphi XE2. Спасибо за ответ. - person kvnDalley; 14.08.2012
comment
Думаю, лучше не говорить, а добавить тег delphi-xe2. Пожалуйста. - person Arioch 'The; 14.08.2012
comment
ввод - строка. Вы должны прочитать в него весь файл, но я уверен, что вы можете найти в Google, как это сделать. Загрузка файла в список строк неверна, потому что вы сказали, что вам не нужно разбивать его на разные строки. Это было бы хрупким и медленным, чем нужно. - person Arioch 'The; 14.08.2012

Я использую написанную мной функцию под названием Fetch. Я думаю, что некоторое время назад я украл эту идею из библиотеки Indy:

function Fetch(var VString: string; ASeperator: string = ','): string;
var   LPos: integer;
begin
  LPos := AnsiPos(ASeperator, VString);
  if LPos > 0 then
  begin
    result := Trim(Copy(VString, 1, LPos - 1));
    VString := Copy(VString, LPos + 1, MAXINT);
  end
  else
  begin
    result := VString;
    VString := '';
  end;
end;

Тогда я бы назвал это так:

var
  value: string;
  line: string;
  profileFile: string;
  profileList: TStringList;
  index: integer;
begin
  if OpenDialog1.Execute then
  begin 
    profileFile := OpenDialog1.FileName;
    if (profileFile = '') or not FileExists(profileFile) then
      exit;

    profileList := TStringList.Create;
    try
      profileList.LoadFromFile(profileFile);

      for index := 0 to profileList.Count - 1 do
      begin
        line := profileList[index];
        Fetch(line, ''''); //discard "Line '"
        value := Fetch(line, '#')
        while (value <> '') and (value[1] <> '''') do //bail when we get to the quote at the end
        begin
           ProcessTheNumber(value); //do whatever you need to do with the number
           value := Fetch(line, '#');
        end;
      end;
    finally
      profileList.Free;
    end;
  end;
end;

Примечание: это было введено в браузере, поэтому я не проверял, работает ли оно.

person Nat    schedule 16.08.2012