【问题标题】:Best method to scan a CSV file for a value in Delphi 7在 Delphi 7 中扫描 CSV 文件以获取值的最佳方法
【发布时间】:2013-09-02 10:35:15
【问题描述】:

我正在寻找有关如何使用 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)从程序内部调用此函数的频率。

你会推荐什么,为什么?

【问题讨论】:

  • 您可以使用初始加载的 AdoDataset 或 Clientdataset 和 CreateDataset 作为 MemoryTable 并使用 Locate 来获取您的值。您还可以构建二叉树或更便宜的记录数组或自己的类列表并搜索它们二进制。根据您的重点,您可以选择最容易实施或最快的解决方案。

标签: delphi delphi-7


【解决方案1】:
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;

【讨论】:

  • Delphi 7 确实有 PosEx 函数,但是 Delphi 7 不知道如何处理 ParseFile 函数中的 FOR S IN SL DO BEGIN。
  • 我已经更新了代码,以向不熟悉 FOR...IN 语法的人展示如何在 Delphi 7 中执行此操作。
【解决方案2】:

与其编写自己的代码,不如使用 TStrings 的可能鲜为人知的 CommaText 属性?

使用 CommaText 的示例如下所示。 代码

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 调用的输出。

安德鲁

英国汉普郡

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 所以您是说使用 LoadFromFile() 将整个文件加载到单个字符串中,然后执行 Pos(#13#10+'2,2,TheString)?
    • 是的,类似的。
    【解决方案4】:

    我想我会创建二维数组

    Book[Chapter, Paragraph]
    

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

    而且功能将是微不足道的:

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

    如果您正在寻找 3-rd 方工具,JEDi 可以选择

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

    【讨论】:

      【解决方案5】:

      对于 2dim 数组,您需要一个 stringlist 助手作为临时对象:

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-12
        • 1970-01-01
        相关资源
        最近更新 更多