正在解析 Delphi 中的文本

Parsing a text in Delphi

我有一个包含以下数据的文本文件:

dgm P1  
s0:->b1  
*s1:b2->b1  
S2:b2->b1,b3  
dgm P2  
s0:->b2  
*s1:b1,b3->b2

我想解析此文件以获取一个数组,其元素将包含每个 dgm 到下一个。也就是说,第一个元素将是:

dgm P1  
s0:->b1  
*s1:b2->b1  
S2:b2->b1,b3

第二个元素将是:

dgm P2  
s0:->b2  
*s1:b1,b3->b2

等 请问我如何在 Delphi 中解决这个问题。我正在寻找一种更好的方法来做到这一点。我尝试从文件加载到 TStringList。

begin
str:=TstringList.Create;
try
str.LoadFromFile('example.txt');
for i:=0 to str.Count -1 do
if str[i] ='dgm' then
 //get the position, add it to an array;
 //get the next position, till the end;
 //use the positions to divide up the string

 finally
 str.Free;

然而,这是行不通的,我也认为可能有更好的方法 比我简要概述的要处理这个。

作为。此答案使用 Delphi 2010+ 的功能,因为它是在主题启动器指定他的目标 Delphi 版本之前编写的。这段代码仍然可以成为他自己使用他可用的库和语言功能实现的框架。

function ParseDgmStringsList( const str: TStrings ): TArray<TArray<String>>;
var
  s: string;
  section: TList<String>;
  receiver: TList<TArray<String>>;

  procedure FlushSection;
  begin
    if section.Count > 0 then begin
       receiver.Add( section.ToArray() );
       section.Clear;
    end;
  end;
begin
  section := nil;
  receiver := TList<TArray<String>>.Create;
  try
    section := TList<String>.Create;

    for s in str do begin
      if StartsText('dgm ', s) then // or StartsStr
         FlushSection;   
      section.Add( s );
    end;

    FlushSection;
    Result := receiver.ToArray();
  finally
    receiver.Destroy;
    section.Free;
  end;
end;

http://docwiki.embarcadero.com/Libraries/Seattle/en/System.Generics.Collections.TList_Properties

PS。请注意,"using AnsiContainsStr(str,'dgm')" 是脆弱的并且很难正确 - 它会在 S2:b2->bcdgmaz,b3 等行产生误报。 您应该检查 dgm 开始字符串并且它是一个单独的单词而不是某个随机较长单词的一部分(换句话说搜索 'dgm' + #32 而不是仅仅 'dgm'

PPS。另一件需要考虑的事情是您将如何处理以非 dgm 行开头的文件?你会用空行、缩进行做什么?例如,您将如何解析这样的文件?

s8:->b2  
;*s1:b1,b3->b2
dgm P1  
s0:->b1  
*s1:b2->b1  

S2:b2->b1,b3  
    dgm P2  
  s0:->b2  
*s1:b1,b3->b2