Разделить строку на массив строк на основе разделителя

Я пытаюсь найти функцию Delphi, которая разделит входную строку на массив строк на основе разделителя. Я нашел много в Google, но у всех, похоже, есть свои проблемы, и мне не удалось заставить их работать.

Мне просто нужно разбить строку типа: "word:doc,txt,docx" на массив на основе ':'. Результат будет ['word', 'doc,txt,docx'].

У кого-нибудь есть функция, которая, как они знают, работает?

Спасибо


person Ryan    schedule 12.04.2010    source источник


Ответы (18)


вы можете использовать свойство TStrings.DelimitedText для разделения строки

проверьте этот образец

program Project28;

{$APPTYPE CONSOLE}

uses
  Classes,
  SysUtils;

procedure Split(Delimiter: Char; Str: string; ListOfStrings: TStrings) ;
begin
   ListOfStrings.Clear;
   ListOfStrings.Delimiter       := Delimiter;
   ListOfStrings.StrictDelimiter := True; // Requires D2006 or newer.
   ListOfStrings.DelimitedText   := Str;
end;


var
   OutPutList: TStringList;
begin
   OutPutList := TStringList.Create;
   try
     Split(':', 'word:doc,txt,docx', OutPutList) ;
     Writeln(OutPutList.Text);
     Readln;
   finally
     OutPutList.Free;
   end;
end.

ОБНОВИТЬ

См. Эту ссылку За пояснения по StrictDelimiter.

person RRUZ    schedule 12.04.2010
comment
К сожалению, во многих старых версиях Delphi есть ошибка (не знаю, в какой версии она была исправлена), в результате которой пробел всегда используется в качестве разделителя. Так что обращайтесь с этим осторожно! - person Leo; 13.04.2010
comment
Ага. Вы захотите установить для StrictDelimiter значение true, и если свойство StrictDelimiter недоступно в вашей версии Delphi, не используйте эту технику! Но если это так, то это очень полезно. - person Mason Wheeler; 13.04.2010
comment
Это не было ошибкой, это было (раздражающим) дизайнерским решением еще в D1 или D2. CommaText должен был заключать любые поля в пробелы в кавычки. Если во входных данных любые поля с пробелами заключены в двойные кавычки, результат правильный. - person Gerry Coll; 13.04.2010
comment
Одна из моих любимых головокружений - это когда люди без нужды помещают указатели типа в имена переменных / параметров. Паскаль строго типизирован - это избыточная типизация (из разнообразия упражнений с пальцами) и вводящая в заблуждение неверная индикация типа, как в этом случае: ArrayOfStrings не массив (и как таковой не даже ответьте на поставленный вопрос). - person Deltics; 13.04.2010
comment
@Deltics, вы правы, имя для переменной выбрано очень плохое, я поменял. спасибо за ваше наблюдение. - person RRUZ; 13.04.2010
comment
Для всех, кто поддерживает этот ответ, обратите внимание, что он не дает массив, как указано в вопросе. Неполная спецификация требований - большая проблема в этой отрасли, игнорирование заявленных требований и предоставление чего-то не запрошенного - еще одна большая проблема. Одобрение любого из них просто способствует плохой практике. ;) - person Deltics; 14.04.2010
comment
Это список, а не массив. - person bvj; 22.02.2014
comment
При использовании D7 установка Delimiter на значение, отличное от пробела по умолчанию, кажется, работает, до тех пор, пока пробел не существует в строке. Это означает, что aStringList.Delimiter:='@'; aStringList.DelimitedText:='One@Two@Three' работает нормально, а aStringList.DelimitedText:='One time@Two times@Three times' не работает должным образом. Итак, замена пробелов на (скажем,) подчеркивания перед назначением .DelimitedText сделает свою работу. - person Vassilis; 07.06.2015

Нет необходимости создавать Split функцию. Он уже существует, см. Classes.ExtractStrings.

Используйте его следующим образом:

program Project1;

{$APPTYPE CONSOLE}

uses
  Classes;

var
  List: TStrings;
begin
  List := TStringList.Create;
  try
    ExtractStrings([':'], [], PChar('word:doc,txt,docx'), List);
    WriteLn(List.Text);
    ReadLn;
  finally
    List.Free;
  end;
end.

И чтобы ответить на вопрос полностью; List представляет желаемый массив с элементами:

List[0] = 'word'
List[1] = 'doc,txt,docx'
person NGLN    schedule 10.01.2012
comment
ExtractStrings очень негибкий: символы возврата каретки, символы новой строки и кавычки (одинарные или двойные) всегда обрабатываются как разделители .; и Примечание: ExtractStrings не добавляет пустые строки в список. - person awmross; 15.03.2013
comment
Проблема не в том, чтобы спроектировать split функцию, а в необходимости TStrings объекта. И из-за негибкости (@awmross) упоминаний я бы предпочел решение Фрэнка - person Wolf; 10.11.2016

Вы можете использовать StrUtils.SplitString.

function SplitString(const S, Delimiters: string): TStringDynArray;

Его описание из документации:

Разбивает строку на разные части, разделенные указанными символами-разделителями.

SplitString разбивает строку на разные части, разделенные указанными символами-разделителями. S - строка, которую нужно разделить. Разделители - это строка, содержащая символы, определенные как разделители.

SplitString возвращает массив строк типа System.Types. TStringDynArray, содержащий разделенные части исходной строки.

person alex    schedule 13.04.2010
comment
Хммм, не в моей версии Delphi 2010 (есть подпрограмма SplitString в XMLDoc и в (Indy unit) IdStrings, но ни один из них не делает то, что хочет плакат, и процедура XMLDoc в любом случае не отображается через интерфейс модуля). - person Deltics; 14.04.2010
comment
функция SplitString (const S, разделители: строка): TStringDynArray; определено в StrUtils.pas - person alex; 27.07.2010
comment
Я не могу включить файл StrUtils.pas (даже если он есть). - person truthseeker; 01.02.2012
comment
Это пример разделения строки на массив. - person bvj; 22.02.2014
comment
лучше всего то, что это принимает разделитель строк в отличие от разделителей символов в других ответах. - person user30478; 05.12.2018

Использование функции SysUtils.TStringHelper.Split, представленной в Delphi XE3:

var
  MyString: String;
  Splitted: TArray<String>;
begin
  MyString := 'word:doc,txt,docx';
  Splitted := MyString.Split([':']);
end.

Это разделит строку с заданным разделителем на массив строк.

person LU RD    schedule 09.04.2015

Я всегда использую что-то подобное:

Uses
   StrUtils, Classes;

Var
  Str, Delimiter : String;
begin
  // Str is the input string, Delimiter is the delimiter
  With TStringList.Create Do
  try
    Text := ReplaceText(S,Delim,#13#10);

    // From here on and until "finally", your desired result strings are
    // in strings[0].. strings[Count-1)

  finally
    Free; //Clean everything up, and liberate your memory ;-)
  end;

end;
person Frank    schedule 13.04.2010
comment
Отличное решение для пользователей старых версий Delphi. - person Wolf; 10.11.2016
comment
Пользователи C ++ Builder 6: соответствующая функция Strutils::AnsiReplaceText - person Wolf; 10.11.2016
comment
Удивительно просто. Работа в Delphi 7 с: list.Text := AnsiReplaceStr(source, delimiter, #13#10);. - person AlainD; 10.11.2017
comment
В Delphi 6 можно использовать SysUtils.StringReplace - person pyfyc; 04.10.2019
comment
Сладкое маленькое решение для Delphi 6. Кстати, ReplaceText (без учета регистра) должен быть StringReplace (с учетом регистра) или AnsiReplaceStr (который просто вызывает StringReplace), о которых уже упоминал @AlainD. - person TByte; 28.06.2021
comment
К сожалению, с этим кодом есть проблема, заключающаяся в том, что новые строки будут разделены, даже если ваш разделитель - это что-то еще (к сожалению, это то, что всегда выполнялось при присвоении .Text). Уродливым промежуточным шагом было бы сначала заменить существующие строки на что-то другое (и снова вернуться после разделения). Вместо этого я написал простой парсер, см. Мой ответ. - person TByte; 29.06.2021

Подобна функции Explode (), предлагаемой Мефом, но с парой отличий (одно из которых я считаю исправлением ошибки):

  type
    TArrayOfString = array of String;


  function SplitString(const aSeparator, aString: String; aMax: Integer = 0): TArrayOfString;
  var
    i, strt, cnt: Integer;
    sepLen: Integer;

    procedure AddString(aEnd: Integer = -1);
    var
      endPos: Integer;
    begin
      if (aEnd = -1) then
        endPos := i
      else
        endPos := aEnd + 1;

      if (strt < endPos) then
        result[cnt] := Copy(aString, strt, endPos - strt)
      else
        result[cnt] := '';

      Inc(cnt);
    end;

  begin
    if (aString = '') or (aMax < 0) then
    begin
      SetLength(result, 0);
      EXIT;
    end;

    if (aSeparator = '') then
    begin
      SetLength(result, 1);
      result[0] := aString;
      EXIT;
    end;

    sepLen := Length(aSeparator);
    SetLength(result, (Length(aString) div sepLen) + 1);

    i     := 1;
    strt  := i;
    cnt   := 0;
    while (i <= (Length(aString)- sepLen + 1)) do
    begin
      if (aString[i] = aSeparator[1]) then
        if (Copy(aString, i, sepLen) = aSeparator) then
        begin
          AddString;

          if (cnt = aMax) then
          begin
            SetLength(result, cnt);
            EXIT;
          end;

          Inc(i, sepLen - 1);
          strt := i + 1;
        end;

      Inc(i);
    end;

    AddString(Length(aString));

    SetLength(result, cnt);
  end;

Отличия:

  1. Параметр aMax ограничивает количество возвращаемых строк
  2. Если входная строка заканчивается разделителем, то считается, что существует номинальная "пустая" конечная строка.

Примеры:

SplitString(':', 'abc') returns      :    result[0]  = abc

SplitString(':', 'a:b:c:') returns   :    result[0]  = a
                                          result[1]  = b
                                          result[2]  = c
                                          result[3]  = <empty string>

SplitString(':', 'a:b:c:', 2) returns:    result[0]  = a
                                          result[1]  = b

Я считаю исправлением ошибки конечный разделитель и условный «пустой конечный элемент».

Я также включил изменение распределения памяти, которое я предложил, с уточнением (я ошибочно предположил, что входная строка может содержать не более 50% разделителей, но, возможно, она, конечно, может состоять из строк разделителей на 100%, давая массив пустых элементов!)

person Deltics    schedule 13.04.2010

Explode - очень высокоскоростная функция, исходный алгоритм которой можно получить из компонента TStrings. Я использую следующий тест для взрыва: Explode 134217733 байта данных, я получаю 19173962 элементов, время работы: 2984 мс.

Implode - это функция с очень низкой скоростью, но я пишу ее легко.

{ ****************************************************************************** }
{  Explode/Implode (String <> String array)                                      }
{ ****************************************************************************** }
function Explode(S: String; Delimiter: Char): Strings; overload;
var I, C: Integer; P, P1: PChar;
begin
    SetLength(Result, 0);
    if Length(S) = 0 then Exit;
    P:=PChar(S+Delimiter); C:=0;
    while P^ <> #0 do begin
       P1:=P;
       while (P^ <> Delimiter) do P:=CharNext(P);
       Inc(C);
       while P^ in [#1..' '] do P:=CharNext(P);
       if P^ = Delimiter then begin
          repeat
           P:=CharNext(P);
          until not (P^ in [#1..' ']);
       end;
    end;
    SetLength(Result, C);
    P:=PChar(S+Delimiter); I:=-1;
    while P^ <> #0 do begin
       P1:=P;
       while (P^ <> Delimiter) do P:=CharNext(P);
       Inc(I); SetString(Result[I], P1, P-P1);
       while P^ in [#1..' '] do P:=CharNext(P);
       if P^ = Delimiter then begin
          repeat
           P:=CharNext(P);
          until not (P^ in [#1..' ']);
       end;
    end;
end;

function Explode(S: String; Delimiter: Char; Index: Integer): String; overload;
var I: Integer; P, P1: PChar;
begin
    if Length(S) = 0 then Exit;
    P:=PChar(S+Delimiter); I:=1;
    while P^ <> #0 do begin
       P1:=P;
       while (P^ <> Delimiter) do P:=CharNext(P);
        SetString(Result, P1, P-P1);
        if (I <> Index) then Inc(I) else begin
           SetString(Result, P1, P-P1); Exit;
        end;
       while P^ in [#1..' '] do P:=CharNext(P);
       if P^ = Delimiter then begin
          repeat
           P:=CharNext(P);
          until not (P^ in [#1..' ']);
       end;
    end;
end;

function Implode(S: Strings; Delimiter: Char): String;
var iCount: Integer;
begin
     Result:='';
     if (Length(S) = 0) then Exit;
     for iCount:=0 to Length(S)-1 do
     Result:=Result+S[iCount]+Delimiter;
     System.Delete(Result, Length(Result), 1);
end;
person Delphi 7    schedule 19.04.2012
comment
Это не компилируется: Strings не является типом. - person NGLN; 10.11.2016

var  
    su  : string;        // What we want split
    si  : TStringList;   // Result of splitting
    Delimiter : string;
    ...
    Delimiter := ';';
    si.Text := ReplaceStr(su, Delimiter, #13#10);

Строки в списке si будут содержать разделенные строки.

person Ihor Konovalenko    schedule 08.07.2015

Вы можете создать свою собственную функцию, которая возвращает TArray строки:

function mySplit(input: string): TArray<string>;
var
  delimiterSet: array [0 .. 0] of char; 
     // split works with char array, not a single char
begin
  delimiterSet[0] := '&'; // some character
  result := input.Split(delimiterSet);
end;
person bob_saginowski    schedule 17.05.2014

Здесь реализована функция разнесения, которая доступен во многих других языках программирования как стандартная функция:

type 
  TStringDynArray = array of String;

function Explode(const Separator, S: string; Limit: Integer = 0): TStringDynArray; 
var 
  SepLen: Integer; 
  F, P: PChar; 
  ALen, Index: Integer; 
begin 
  SetLength(Result, 0); 
  if (S = '') or (Limit < 0) then Exit; 
  if Separator = '' then 
  begin 
    SetLength(Result, 1); 
    Result[0] := S; 
    Exit; 
  end; 
  SepLen := Length(Separator); 
  ALen := Limit; 
  SetLength(Result, ALen); 

  Index := 0; 
  P := PChar(S); 
  while P^ <> #0 do 
  begin 
    F := P; 
    P := AnsiStrPos(P, PChar(Separator)); 
    if (P = nil) or ((Limit > 0) and (Index = Limit - 1)) then P := StrEnd(F); 
    if Index >= ALen then 
    begin 
      Inc(ALen, 5); 
      SetLength(Result, ALen); 
    end; 
    SetString(Result[Index], F, P - F); 
    Inc(Index); 
    if P^ <> #0 then Inc(P, SepLen); 
  end; 
  if Index < ALen then SetLength(Result, Index); 
end; 

Пример использования:

var
  res: TStringDynArray;
begin
  res := Explode(':', yourString);
person Leo    schedule 12.04.2010
comment
В этом коде есть несколько странных и потенциально чрезвычайно неэффективных вариантов управления / прогнозирования продолжительности результата. Постепенно увеличивая результирующий массив, увеличиваются шансы перераспределения памяти и фрагментации. Более эффективным было бы установить начальную длину настолько большой, насколько это возможно, т.е. предположить, что входная строка состоит из 50% разделительных строк = Length (S) div (2 * Length (Separator). Затем установите его на фактическое количество по завершении: 1 выделение, за которым, возможно, следует одно усечение. - person Deltics; 13.04.2010
comment
Также вы не объясняете назначение параметра Limit. Я интуитивно ожидал, что он установит максимальное количество возвращаемых подстрок, хотя на самом деле он, кажется, ограничивает обнаружение подстрок первым предельным числом символов во входной строке. Это кажется бессмысленным, поскольку, если вам нужно это сделать, вы можете просто использовать Explode () над Copy () требуемой подстроки. Гораздо полезнее было бы использовать Limit для установки максимального количества подстрок. - person Deltics; 13.04.2010
comment
@Deltics: Никто не утверждал, что это высокооптимизированная функция, и никто не просил об этом, поэтому я не понимаю вашу жалобу. Но, может быть, вы один из тех, кто оптимизирует все, независимо от того, нужно это или нет ... - person Leo; 14.04.2010
comment
Я из тех парней, которые не пишут излишне неэффективный код, а потом не беспокоятся об оптимизации. Речь шла не о тщательном анализе кода и нахождении небольшого потенциала оптимизации, это была просто очевидная и легко решаемая неэффективность: постепенный рост непрерывной памяти, которая вместо этого может быть легко предварительно выделена и впоследствии усечена. - person Deltics; 15.04.2010
comment
Также @Mef: И это не была жалоба, это был комментарий, наблюдение. Но что более важно, ваш код также содержал то, что я считаю ошибкой (см. Мою альтернативу для объяснения). - person Deltics; 15.04.2010

Я написал эту функцию, которая возвращает связанный список строк, разделенных определенным разделителем. Чистый бесплатный паскаль без модулей.

Program split_f;

type
    PTItem = ^TItem;
    TItem = record
        str : string;
        next : PTItem;
    end;

var
    s : string;
    strs : PTItem;

procedure split(str : string;delim : char;var list : PTItem);
var
    i : integer;
    buff : PTItem;
begin
    new(list);
    buff:= list;
    buff^.str:='';
    buff^.next:=nil;

    for i:=1 to length(str) do begin
        if (str[i] = delim) then begin
            new(buff^.next);
            buff:=buff^.next;
            buff^.str := '';
            buff^.next := nil;
        end
        else
        buff^.str:= buff^.str+str[i];
    end;
end;

procedure print(var list:PTItem);
var
    buff : PTItem;
begin
    buff := list;
    while buff<>nil do begin
        writeln(buff^.str);
        buff:= buff^.next;
    end;
end;

begin

    s := 'Hi;how;are;you?';

    split(s, ';', strs);
    print(strs);


end.
person Aleš Oskar Kocur    schedule 22.05.2014

Библиотека Jedi Code Library предоставляет расширенный StringList со встроенной функцией Split, которая способна как добавлять, так и заменять существующий текст. Он также предоставляет интерфейс с подсчетом ссылок. Таким образом, это можно использовать даже со старыми версиями Delphi, в которых нет SplitStrings, и без осторожной и немного утомительной настройки стандартного TStringList, чтобы использовать только указанные разделители.

Например, для данного текстового файла со строками типа Dog 5 4 7 их можно проанализировать, используя:

var slF, slR: IJclStringList; ai: TList<integer>; s: string; i: integer;
    action: procedure(const Name: string; Const Data: array of integer);

slF := TJclStringList.Create; slF.LoadFromFile('some.txt');
slR := TJclStringList.Create;
for s in slF do begin
    slR.Split(s, ' ', true);
    ai := TList<Integer>.Create;
    try
       for i := 1 to slR.Count - 1 do
           ai.Add(StrToInt(slR[i]));
       action(slR[0], ai.ToArray);
    finally ai.Free; end;
end; 

http://wiki.delphi-jedi.org/wiki/JCL_Help:IJclStringList.Split@string@string@Boolean

person Arioch 'The    schedule 22.01.2013

Это решит вашу проблему

interface
   TArrayStr = Array Of string;

implementation

function SplitString(Text: String): TArrayStr;
var
   intIdx: Integer;
   intIdxOutput: Integer;
const
   Delimiter = ';';
begin
   intIdxOutput := 0;
   SetLength(Result, 1);
   Result[0] := ''; 

   for intIdx := 1 to Length(Text) do
   begin
      if Text[intIdx] = Delimiter then
      begin
         intIdxOutput := intIdxOutput + 1;
         SetLength(Result, Length(Result) + 1);
      end
      else
         Result[intIdxOutput] := Result[intIdxOutput] + Text[intIdx];
   end;
end;
person Dennis    schedule 30.01.2015
comment
Не могли бы вы объяснить, что делает код? Спасибо - person Paco; 30.01.2015
comment
он проходит через переданную строку в поисках разделителя const, если не найден, объединяется с текущей позицией в массиве, при нахождении переходит к следующей позиции в динамическом массиве - person Dennis; 02.02.2015

Моя любимая функция для разделения:

procedure splitString(delim: char; s: string; ListOfStrings: TStrings);
var temp: string;
    i: integer;
begin
   ListOfStrings.Clear;
   for i:=1 to length(s) do
    begin
      if s[i] = delim then
        begin
          ListOfStrings.add(temp);
          temp := '';
        end
      else
        begin
          temp := temp + s[i];
          if i=length(s) then
             ListOfStrings.add(temp);
        end;
    end;
    ListOfStrings.add(temp);
end;
person John Boe    schedule 22.09.2018
comment
Последний элемент был пропущен в вашей функции - person alijunior; 31.10.2018
comment
Вам нужно добавить ListOfStrings.add(temp); после цикла, чтобы добавить последний элемент. - person rnso; 10.07.2019
comment
Спасибо за заметку, я редактировал код в блоке else. - person John Boe; 18.07.2019

В базе ответа NGLG https://stackoverflow.com/a/8811242/6619626 вы можете использовать следующую функцию:

type
OurArrayStr=array of string;

function SplitString(DelimeterChars:char;Str:string):OurArrayStr;
var
seg: TStringList;
i:integer;
ret:OurArrayStr;
begin
    seg := TStringList.Create;
    ExtractStrings([DelimeterChars],[], PChar(Str), seg);
    for i:=0 to seg.Count-1 do
    begin
         SetLength(ret,length(ret)+1);
         ret[length(ret)-1]:=seg.Strings[i];
    end;
    SplitString:=ret;
    seg.Free;
end;

Работает во всех версиях Delphi.

person Reza Mousavi    schedule 15.12.2017

Для delphi 2010 вам нужно создать свою собственную функцию разделения.

function Split(const Texto, Delimitador: string): TStringArray;
var
  i: integer;
  Len: integer;
  PosStart: integer;
  PosDel: integer;
  TempText:string;
begin
  i := 0;
  SetLength(Result, 1);
  Len := Length(Delimitador);
  PosStart := 1;
  PosDel := Pos(Delimitador, Texto);
  TempText:=  Texto;
  while PosDel > 0 do
    begin
      Result[i] := Copy(TempText, PosStart, PosDel - PosStart);
      PosStart := PosDel + Len;
      TempText:=Copy(TempText, PosStart, Length(TempText));
      PosDel := Pos(Delimitador, TempText);
      PosStart := 1;
      inc(i);
      SetLength(Result, i + 1);
    end;
  Result[i] := Copy(TempText, PosStart, Length(TempText));
end;

Вы можете называть это так

type
  TStringArray = array of string;
var Temp2:TStringArray;
Temp1="hello:world";
Temp2=Split(Temp1,':')
person user3609960    schedule 16.05.2018

Сначала я похвалил ответ от @Frank, так как мне нужно было что-то, что работает для Delphi 6, и, похоже, оно сработало. Однако с тех пор я обнаружил, что в этом решении есть ошибка, из-за которой оно по-прежнему разбивается на # 13 # 10 независимо от разделителя. Отлично работает, если вы не ожидаете строк в исходной строке.

Я написал простой парсер, который работает только с односимвольными разделителями. Примечание: он помещает значения в TStrings, а не в массив, как запрошено оператором, но может быть легко изменен для адаптации к массивам.

Вот процедура:

procedure SplitString(const ASource: string; const ADelimiter: Char; AValues: TStrings);
var
  i, lastDelimPos: Integer;
begin
  AValues.Clear;
  lastDelimPos := 0;

  for i := 1 to Length(ASource) do
    if ASource[i] = ADelimiter then
    begin
      if lastDelimPos = 0 then
        AValues.Add(CopyRange(ASource, 1, i - 1))
      else
        AValues.Add(CopyRange(ASource, lastDelimPos + 1, i - 1));
      lastDelimPos := i;
    end;

  if lastDelimPos = 0 then
    AValues.Add(ASource)
  else
    AValues.Add(CopyRange(ASource, lastDelimPos + 1, MaxInt));
end;

function CopyRange(const s: string; const AIndexFrom, AIndexTo: Integer): string;
begin
  Result := Copy(s, AIndexFrom, AIndexTo - AIndexFrom + 1);
end;

Примечание: согласно C # string.Split () пустая входная строка приведет к единственной пустой строке в TStrings. Точно так же наличие одного ограничителя в качестве входной строки приведет к появлению двух пустых строк в TStrings.

Вот примерный тестовый код, который я использовал, чтобы убедиться в его надежности:

procedure AddTest(const ATestLine: string; const AExpectedResult: array of string);
var
  expectedResult: TStringList;
  i: Integer;
begin
  expectedResult := TStringList.Create;
  for i := 0 to Length(AExpectedResult) - 1 do
    expectedResult.Add(AExpectedResult[i]);
  testStrings.AddObject(ATestLine, expectedResult);
end;

//====================

AddTest('test', ['test']);
AddTest('', ['']);
AddTest(',', ['', '']);
AddTest('line1' + #13#10 + ',line 2,line3, line 4', ['line1' + #13#10, 'line 2', 'line3', ' line 4']);
AddTest('line1' + #13#10 + 'd,line 2,line3, line 4', ['line1' + #13#10 + 'd', 'line 2', 'line3', ' line 4']);
AddTest('line1,line 2,line3, line 4', ['line1', 'line 2', 'line3', ' line 4']);
AddTest('test, ', ['test', ' ']);
AddTest('test,', ['test', '']);
AddTest('test1,test2 ', ['test1', 'test2 ']);
AddTest('test1,test2', ['test1', 'test2']);
AddTest('test1,test2, ', ['test1', 'test2', ' ']);
AddTest('test1,test2,', ['test1', 'test2', '']);

//====================

testFailed := False;
for i := 0 to testStrings.Count - 1 do
begin
  SplitString2(testStrings[i], ',', f);
  log('Test ID=%d', [i]);
  log('    Test String="%s"', [testStrings[i]]);
  log('    Item count=%d', [f.Count]);
  testResult := TStringList(TestStrings.Objects[i]);
  if testResult.Count <> f.Count then
  begin
    Log('!!');
    Log('!! Count mismatch. Got=%d, Expected=%d', [f.Count, testResult.Count]);
    Log('!!');

    testFailed := True;
  end;

  for j := 0 to f.Count - 1 do
  begin
    log('    Item %d="%s"    (len=%d)', [j, f[j], Length(f[j])]);
    if testResult[j] <> f[j] then
    begin
      Log('!!');
      Log('!! Text mismatch. Got="%s", Expected="%s"', [f[j], testResult[j]]);
      Log('!!');

      testFailed := True;
    end;
  end;
end;

Изменить: код для функции CopyRange () отсутствовал, добавлен сейчас. Виноват.

person TByte    schedule 29.06.2021

person    schedule
comment
Ответы, которые ясно и лаконично объясняют решение, гораздо полезнее, чем ответы, содержащие только код. - person MartynA; 16.11.2018