我有一个庞大的文件,我必须逐行解析.速度至关重要.
一行示例:
Token-1 Here-is-the-Next-Token Last-Token-on-Line ^ ^ Current Position Position after GetToken
调用GetToken,返回"Here-is-the-Next-Token"并将CurrentPosition设置为令牌最后一个字符的位置,以便为下次调用GetToken做好准备.令牌由一个或多个空格分隔.
假设文件已经在内存中的StringList中.它很容易适合内存,比如200 MB.
我只担心解析的执行时间.什么代码将在Delphi(Pascal)中产生绝对最快的执行?
使用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;