在Delphi 7中扫描CSV文件以获取值的最佳方法

时间:2013-09-02 10:35:16

标签: delphi delphi-7

我正在寻找有关如何使用Delphi 7最好地处理编程任务的建议。

我需要能够快速识别CSV文件中的值(大小小于15kb)。 CSV文件的格式为:

章节编号,段落编号,段落中的总字数

我希望能够通过提供前两个值(即章节和段落编号)的函数来检索最后一个值,即单词数。

CSV文件按数字排序,即:

1,1,30    // first paragraph of first chapter  (line # 1)
1,2,56    // second paragraph of first chapter  (line # 2)
1,3,101
1,4,56
...
2,1,78
2,2,51
...
100,1,87
100,2,101
...
100,23,78    // last paragraph of last chapter (line # 1500)

所以在上面的例子中,我想将2,2传递给一个函数并让它返回“51”(整数)

我想避免使用数据库表,因为:1)数据量不是很大(CSV文件中有1500行,即1500段),2)数据库引擎的额外开销(我只需要读取数据,而不是写入数据),3)从程序中调用此函数的频率。

你会推荐什么,为什么?

5 个答案:

答案 0 :(得分:3)

TYPE
  TTwoDimIntArr = ARRAY OF ARRAY OF Cardinal;

PROCEDURE SetValue(VAR ARR : TTwoDimIntArr ; Chapter,Paragraph,Value : Cardinal);
  BEGIN
    IF Chapter>=LENGTH(ARR) THEN SetLength(ARR,SUCC(Chapter));
    IF Paragraph>=LENGTH(ARR[Chapter]) THEN SetLength(ARR[Chapter],SUCC(Paragraph));
    ARR[Chapter,Paragraph]:=Value
  END;

FUNCTION GetValue(CONST ARR : TTwoDimIntArr ; Chapter,Paragraph : Cardinal) : Cardinal;
  BEGIN
    IF Chapter>=LENGTH(ARR) THEN
      Result:=0
    ELSE IF Paragraph>=LENGTH(ARR[Chapter]) THEN
      Result:=0
    ELSE
      Result:=ARR[Chapter,Paragraph]
  END;

FUNCTION ParseFile(CONST FileName : STRING) : TTwoDimIntArr;
  VAR
    SL  : TStrings;
    S   : STRING;
    P,Q : Cardinal;
    {$IFDEF DELPHI7 }
      I : Cardinal;
    {$ENDIF }

  BEGIN
    SL:=TStringList.Create;
    TRY
      SL.LoadFromFile(FileName);
      {$IFDEF DELPHI7 }
      FOR I:=1 TO SL.Count DO BEGIN
        S:=SL[PRED(I)];
      {$ELSE }
      FOR S IN SL DO BEGIN
      {$ENDIF }
        P:=POS(',',S);
        Q:=PosEx(',',S,SUCC(P));
        SetValue(Result,StrToInt(COPY(S,1,PRED(P))),StrToInt(COPY(S,SUCC(P),PRED(Q-P))),StrToInt(COPY(S,SUCC(Q),255)))
      END
    FINALLY
      SL.Free
    END
  END;

ParseFile解析文件并将其以二维动态数组返回。如果您100%确定不超出阵列的边界,则可以直接访问它。否则,GetValue函数是一个安全的包装器,用于访问数组的内容。

将其用作:

USES ... StrUtils ...;

.
.<My Code>
.
VAR ARR : TTwoDimIntArr;

BEGIN
  ARR:=ParseFile(<FileName>);
  .
  .
  .
  Words:=GetValue(ARR, <Chapter>, <Paragraph>);
  .
  .
END.

如果Delphi 7在StrUtils中没有PosEx函数,您可以按如下方式编写代码:

FUNCTION PosEx(CONST SearchFor,SearchIn : STRING ; StartPos : Cardinal = 1) : Cardinal;
  BEGIN
    Result:=POS(SearchFor,COPY(SearchIn,StartPos,$7FFFFFFF));
    IF Result>0 THEN INC(Result,PRED(StartPos))
  END;

答案 1 :(得分:2)

为什么不使用TStrings的可能鲜为人知的CommaText属性而不是编写自己的代码?

使用CommaText的示例如下所示。 CODE

var
  s: TStringList;
begin
  s := TStringList.Create;
  try
    s.CommaText := 'a, b, "c,d"';
    ShowMessage( s[0] );
    ShowMessage( s[1] );
    ShowMessage( s[2] );
  finally
    s.Free;
  end;
end;
  

将显示引用:a b c,d

作为三个ShowMessage调用的输出。

安德鲁

英国汉普郡

答案 2 :(得分:1)

如果文件不是那么大(〜几千字节),我建议将其读入内存,并搜索#13#10','。此字符串后面的下一个数字将是您要搜索的数字(当然,如果您的文件中没有多余的空格)。

答案 3 :(得分:1)

我想我会创建二维数组

Book[Chapter, Paragraph]

并通过阅读文件手动填写。

这个功能很简单:

GetNumberOfPages(Chapter: integer; Paragraph: integer): integer;
begin
  Result := Book[Chapter, Paragraph];
end;

如果您正在寻找第三方工具,JEDi可以选择

http://wiki.delphi-jedi.org/wiki/JVCL_Help:TJvCsvDataSet

答案 4 :(得分:0)

使用2dim数组,您需要一个stringlist helper作为temp:

BEGIN
    SL:=TStringList.Create;
    sltemp:= TStringList.Create;
   TRY
      SL.LoadFromFile(FileName);
      writeln('Scikit Boston Samples: '+itoa(sl.count-1))
       FOR I:= 0 TO SL.Count-1 DO BEGIN
        S:=SL[(I)];
        SLtemp.CommaText:= S;
        for sll:= start-1 to col-1 do   
          SetValue(Result,I,Sll,StrToFloat(sltemp[sll]))
       END;
   FINALLY
      sltemp.free;
      SL.Free
   END