字符串列表以字符串为分隔符?

3

我有一个对象中的属性叫做HistoryText,以字符串形式存储。 我想要在网格中显示所有行。我应该能够删除和编辑网格中的行。 格式如下:

16.5.2003-$-12:09-$-anna-$-Organization created
2.6.2005-$-13:03-$-jimmy-$-Organization edited
19.12.2005-$-13:33-$-madeleine-$-Organization edited

所以每一行都有四个字段:日期、时间、用户和消息,使用'-$-'作为分隔符。

由于分隔符是字符串而不是字符,因此无法将其分配给字符串列表的分隔符属性。

我有一个例程来将字符串提取到字符串列表中:

procedure ParseDelimited(const aStringList: TStringList; const aOrgList, aDelimiter: string);
var
   vDelimiterPos : integer;
   vPartialStr : string;
   vRemaingTxt : string;
   vDelimiterLength : integer;
begin
   vDelimiterLength := Length(aDelimiter);

   if (AnsiRightStr(aOrgList, Length(aDelimiter)) = aDelimiter) then
     vRemaingTxt := aOrgList
   else
     vRemaingTxt := aOrgList + aDelimiter;

   aStringList.BeginUpdate;
   aStringList.Clear;
   try
     while Length(vRemaingTxt) > 0 do
     begin
       vDelimiterPos := Pos(aDelimiter, vRemaingTxt);
       vPartialStr := Copy(vRemaingTxt,0,vDelimiterPos-1);
       aStringList.Add(vPartialStr);
       vRemaingTxt := Copy(vRemaingTxt,vDelimiterPos+vDelimiterLength,MaxInt);
     end;
   finally
     aStringList.EndUpdate;
   end;
end;

看起来一切都运行良好。我的问题是如何将StringList中的更改同步回原始的字符串属性?由于该分隔符具有如此多的历史数据,因此我认为将其更改为TChar并不是一个现实的选择。

更新: 澄清一下,我认为我可以使用上述方法将String转换为StringList。那么在网格中显示它应该不难。问题出现在当我想要将TStringList转换回带有'-$-'作为分隔符的原始String属性时。例如,我不能使用HistoryText:= myStringList.Delimitedtext。

第二次更新: 我已经解决了。你们所有人都得到了+1分的快速答案和真正想要帮助的奖励。总结一下我是如何做到的。

从Historytext中读取:

MyStringList.Text := Historytext;

现在每行都有3个'-$-'的分隔符,每行像往常一样用换行符分隔。

  • 循环解析Stringlist并将其显示在网格中。不再关心MyStringList。
  • 让用户删除和编辑网格中的行。
  • 完成后按行和列循环网格,并使用与原始格式相同的格式构建一个新字符串。
  • 将该字符串分配给HistoryText。

所以将重点从StringList转移到网格中使它更容易 :)


您的实际问题是什么?您提到想要在网格中显示,而字符串列表过程“似乎运行良好”。同时,“将更改同步回来”也有点宽泛。您需要什么帮助吗? - Tobiasopdenbrouw
我的解决方案在D2007+中都可以工作,并且更加简短。 - Uwe Raabe
请注意,更优雅的方法是使用pos和strutils posex,并且不需要进行任何复制操作。 - Marco van de Voort
2个回答

7

除了分隔符(一个字符)和DelimitedText,您还可以使用LineBreak(一个字符串)和Text:

lst := TStringList.Create;
try
  lst.LineBreak := '-$-';
  lst.Text := '16.5.2003-$-12:09-$-anna-$-Organization created';
  Memo1.Lines := lst;  // or whatever you do with it
finally
  lst.Free;
end;

Ans它甚至可以反过来使用。

嘿,这个不错。你知道是在哪个 Delphi 版本中引入的吗? - Marjan Venema
抱歉,但我不明白它的意思。 字符串属性中的每一行都以回车+换行符分隔。所以真正的字符串是:16.5.2003-$-12:09-$-anna-$-创建组织#D#A 2.6.2005-$-13:03-$-jimmy-$-编辑组织#D#A 19.12.2005-$-13:33-$-madeleine-$-编辑组织#D#Alst := TStringList.Create; try lst.LineBreak := '-$-'; lst.Text := myObject.HistoryText // 例如在网格中使用列表 finally lst.Free; end;这是你的意思吗? - Roland Bengtsson
@Uwe,@Marjan:TStrings.LineBreak属性在Delphi 2006中引入。 - Jeroen Wiert Pluimers
嗯,就按照我的回答来做,或者使用两个字符串列表。您可以先将HistoryText赋值给第一个字符串列表,然后逐个处理该字符串列表中的所有项目。将第一个字符串列表中的每个字符串分配给第二个字符串列表的文本。这应该设置其linebreak属性为'-$-'以将每一行拆分成字段。每个字段应该是第二个字符串列表中的一个项目。要返回到HistoryText,您需要反向执行相同的操作:将每个列值添加到第二个字符串列表中,然后将其整个文本添加到第一个中,清除第二个,重复每一行。 - Marjan Venema
在我的回答中添加了一个使用两个字符串列表的示例。 - Marjan Venema
@Roland:我认为您的意思是将文本拆分为一行,以便结果字符串列表中的索引类似于字符串网格的列。如果您只有一个大字符串,则必须首先使用带有#D#A换行符的字符串列表将其分成单独的行,并使用第二个字符串列表将每行分成字段,就像Marjan在他的示例中所显示的那样,正如我刚刚意识到的那样。 - Uwe Raabe

2

根据你提供的信息,很难确定你的问题:

按照网格行进行操作:

  • 对于每一行:
    • 将一个空字符串赋值给临时字符串变量
    • 对于每一列,将行/列值加上分隔符添加到临时字符串变量中
    • 从临时字符串变量中删除最后一个分隔符(如果它不为空)
    • 将临时字符串变量添加到字符串列表中
  • 将字符串列表的文本属性写回到您的 HistoryText 中

const
  Delimiter = '-$-';
var
  row: Integer;
  col: Integer;
  SL: TStringList;
  rowString: string;
begin
  SL := TStringList.Create;
  try
    for row := 0 to StringGrid1.RowCount - 1 do begin
      rowString := '';
      for col := 0 to StringGrid1.ColCount - 1 do begin
        rowString := StringGrid1.Cells[col, row] + Delimiter;
      end;
      if rowString <> '' then begin
        rowString := Copy(rowString, 1, Length(rowString) - Length(Delimiter));
      end;
      SL.Add(rowString);
    end;
    HistoryText := SL.Text;
  finally
    SL.Free;
  end;
end;

使用Uwe的解决方案中TStrings的LineBreak属性:
var
  row: Integer;
  col: Integer;
  SLRows: TStringList;
  SLCols: TStringlist;
begin
  SLRows := TStringList.Create;
  try
    SLCols := TStringList.Create;
    try
      SLCols.LineBreak := '-$-';
      for row := 0 to StringGrid1.RowCount - 1 do begin
        SLCols.Clear;
        for col := 0 to StringGrid1.ColCount - 1 do begin
          SLCols.Add(StringGrid1.Cells[col, row]);
        end;
        SLRows.Add(SLCols.Text);
      end;
      HistoryText := SLRows.Text;
    finally
      SLCols.Free;
    end;
  finally
    SLRows.Free;
  end;
end;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接