如何快速解析ANSI字符串?

时间:2014-06-16 14:15:40

标签: delphi

我有一个大的ansi文本文件。该文件包含许多条目(数百万到数十亿)。每个条目都有4行,如下所示:

@Instrument:6:73:941:1973#0/1
other stuff2
other stuff3
other stuff4

我对第一行很感兴趣。从第一行开始,我需要提取其内容(数字和字符串)。我使用StringReplace替换:并将空格替换为#13,然后我将该行拆分为如下记录:

   TYPE
      RBlock= record                                     // @Instrument:6:73:941:1973#0/1
       Instrument: String;                               // Instrument
       Lane: Integer;                                    // 6  
       TileNo: Integer;                                  // 73
       X: integer;                                       // 941
       Y: Integer;                                       // 1973
       Pair: Byte;                                       // could be 1 or 2 
       MultiplexID: AnsiString;                          // #0  <----  I need it as AnsiString
      end;

使用StrToInto将文本转换为数字可能会很慢,因为它首先将AnsiString转换为字符串。

关于如何更快地阅读它的任何想法将不胜感激。

更新:该行还可以采用其他格式:@Instrument:136:FC6:2:2104:15343:197393 1:Y:18:TACA

2 个答案:

答案 0 :(得分:2)

您需要检查数据并检查可能出现的数据类型。就个人而言,我可能会做这样的事情(对于第一个例子):

procedure ParseLine(const aLine: RawByteString; var aInstrument: string; var
    aLane, aTileNo, aX, aY: Integer; var aMultiplexID: Ansistring; var aPair:
    Byte);
var
  arrayIndex: Integer;
  index: Integer;
  lineLength: Integer;
  NumList: array[0..3] of Integer;
  I: Integer;
  multiEnd: Integer;
begin
  lineLength := Length(aLine);
  // Get the aInstrument
  index := Pos(':', aLine);
  SetLength(aInstrument, index - 2);
  for I := 2 to index - 1 do
    aInstrument[I-1] := Char(aLine[I]);
  // Get the integers
  arrayIndex := 0;
  FillMemory(@NumList, SizeOf(NumList), 0);
  while (index < lineLength) and (arrayIndex < 4) do
  begin
    Inc(index);
    if (aLine[index] = ':') or (aLine[index] = '#') then
      Inc(arrayIndex)
    else
      NumList[arrayIndex] := NumList[arrayIndex] * 10 + Ord(aLine[index]) - Ord('0');
  end;
  aLane := NumList[0];
  aTileNo := NumList[1];
  aX := NumList[2];
  aY := NumList[3];
  // Get the Multiplex
  multiEnd := Pos('/', aLine, index);
  SetLength(aMultiplexID, multiEnd - index - 1);
  Inc(index);
  for I := index to multiEnd - 1 do
    aMultiplexID[I-index+1] := aLine[I];
  // Get the aPair
  if (multiEnd+1 < lineLength) then
    aPair := Ord(aLine[multiEnd+1]) - Ord('0')
  else
    aPair := 0;
end;

这可以进行更多优化,但这将开始真正达到可读性。这里的问题是数据是否对此例程有效。它将处理一个字符串,该字符串太短但文本中的值无效,尽管它太短时不会返回错误。否定数字也是一个问题。您需要注意的是您的数据,它的外观,损坏或无效数据的可能性以及速度对您的重要程度。这是一种平衡的行为。您可以删除所有检查并将其更快或添加更多检查,这将减慢它。

答案 1 :(得分:-1)

在C / C ++中,有一个名为sscanf()的函数,就像这样。

我见过Delphi的几个实现。使用谷歌搜索,因为他们不喜欢你在这里发布外部链接的链接,并且发布一个完整的怪异库函数的所有源代码而不仅仅是作为回复的链接似乎很愚蠢。

您也可以尝试使用正则表达式将字符串拆分为多个部分。

我不确定这些与这里提到的字符串函数在性能方面的比较,但它们值得考虑。

(提示:通过编写专为这些字符串设计的简短解析器,您将获得最佳性能。)