在Delphi中解析一行的最快方法是什么?

lke*_*ler 9 delphi parsing pascal token

我有一个庞大的文件,我必须逐行解析.速度至关重要.

一行示例:

Token-1   Here-is-the-Next-Token      Last-Token-on-Line
      ^                        ^
   Current                 Position
   Position              after GetToken
Run Code Online (Sandbox Code Playgroud)

调用GetToken,返回"Here-is-the-Next-Token"并将CurrentPosition设置为令牌最后一个字符的位置,以便为下次调用GetToken做好准备.令牌由一个或多个空格分隔.

假设文件已经在内存中的StringList中.它很容易适合内存,比如200 MB.

我只担心解析的执行时间.什么代码将在Delphi(Pascal)中产生绝对最快的执行?

Bar*_*lly 33

  • 使用PChar递增处理速度
  • 如果不需要某些令牌,则仅按需复制令牌数据
  • 实际扫描字符时,将PChar复制到局部变量
  • 将源数据保存在单个缓冲区中,除非您必须逐行处理,即使这样,也要考虑将行处理作为词法分析器识别器中的单独标记处理
  • 如果您肯定知道编码,请考虑直接处理来自文件的字节数组缓冲区; 如果使用Delphi 2009,请使用PAnsiChar而不是PChar,除非您知道编码是UTF16-LE.
  • 如果您知道唯一的空格将是#32(ASCII空间),或者类似的一组字符,可能会有一些聪明的位操作黑客,可以让您使用整数扫描一次处理4个字节.我不希望在这里获得大胜,并且代码将像泥浆一样清晰.

这是一个非常有效的样本词法分析器,但它假设所有源数据都在一个字符串中.由于令牌非常长,重写它以处理缓冲区是相当棘手的.

type
  TLexer = class
  private
    FData: string;
    FTokenStart: PChar;
    FCurrPos: PChar;
    function GetCurrentToken: string;
  public
    constructor Create(const AData: string);
    function GetNextToken: Boolean;
    property CurrentToken: string read GetCurrentToken;
  end;

{ TLexer }

constructor TLexer.Create(const AData: string);
begin
  FData := AData;
  FCurrPos := PChar(FData);
end;

function TLexer.GetCurrentToken: string;
begin
  SetString(Result, FTokenStart, FCurrPos - FTokenStart);
end;

function TLexer.GetNextToken: Boolean;
var
  cp: PChar;
begin
  cp := FCurrPos; // copy to local to permit register allocation

  // skip whitespace; this test could be converted to an unsigned int
  // subtraction and compare for only a single branch
  while (cp^ > #0) and (cp^ <= #32) do
    Inc(cp);

  // using null terminater for end of file
  Result := cp^ <> #0;

  if Result then
  begin
    FTokenStart := cp;
    Inc(cp);
    while cp^ > #32 do
      Inc(cp);
  end;

  FCurrPos := cp;
end;
Run Code Online (Sandbox Code Playgroud)