Stringlist和CSV

2 delphi delphi-xe2

在将此CSV文件加载到其中后,如何基于Stringlist中的索引访问各个记录.

CSV示例:

   Record0;Record1;Record2
   Record0;Record1;Record2
   Record0;Record1;Record2
   Record0;Record1;Record2
Run Code Online (Sandbox Code Playgroud)

Sir*_*ufo 7

您不能将RFCtringList用于RFC4180中描述的CSV文件

有效RFC4180 CSV文件示例(2行,5个字段)

Data1;"Data2;Data2";"Data3
Data3";"Data4""Data4""";Data5
Data1;"Data2;Data2";"Data3
Data3";"Data4""Data4""";Data5
Run Code Online (Sandbox Code Playgroud)

和单个字段值

  1. 数据1
  2. 数据2,数据2
  3. 数据3#13#10Data3
  4. 数据4"数据4"
  5. DATA5

但也许你觉得这个可用(我在2011年写的快速样本).

不要混淆,您可以修改单元格值但不能修改SaveToFile方法.

unit CSVData;

interface

type
  TCSVData = class
  private
    FData : array of array of string;
    FDelim : Char;
    FQuote : Char;
    function GetRows : Integer;
    function GetCols : Integer;
    function GetCell( Row, Col : Integer ) : string;
    procedure SetCell( Row, Col : Integer; const Value : string );
  public
    destructor Destroy; override;
    procedure LoadFromFile( const FileName : string );
    property Cell[Row, Col : Integer] : string
      read GetCell
      write SetCell;
    property Rows : Integer
      read GetRows;
    property Cols : Integer
      read GetCols;
    property Delim : Char
      read FDelim
      write FDelim;
    property Quote : Char
      read FQuote
      write FQuote;
  end;

implementation

uses
  Classes;

{ TCSVData }

destructor TCSVData.Destroy;
begin
  SetLength( FData, 0, 0 );
  inherited;
end;

function TCSVData.GetCell( Row, Col : Integer ) : string;
begin
  Result := FData[Row, Col];
end;

function TCSVData.GetCols : Integer;
begin
  if Rows > 0
  then
    Result := Length( FData[0] )
  else
    Result := 0;
end;

function TCSVData.GetRows : Integer;
begin
  Result := Length( FData );
end;

procedure TCSVData.LoadFromFile( const FileName : string );
var
  Data : TStrings;
  Val : string;
  MyChar : Char;
  LastChar : Char;
  QuotePart : Boolean;
  Col : Integer;
  Row : Integer;
  MaxCol : Integer;
begin
  Data := TStringList.Create;
  try
    Data.LoadFromFile( FileName );

    LastChar := #0;
    QuotePart := False;
    Val := '';
    MaxCol := 0;
    Col := 0;
    Row := 0;

    // Jedes Zeichen durchlaufen
    for MyChar in Data.Text do
      begin
        if ( MyChar = Quote )
        then
          begin
            // QuotePart wechselt den Status
            QuotePart := not QuotePart;

            // Befinden wir uns im QuotePart und das letzte Zeichen
            // war das Quote-Zeichen, dann handelt es sich um eine
            // Verdoppelung und wir hängen das Quote-Zeichen an
            // den Puffer
            if QuotePart and ( LastChar = Quote )
            then
              Val := Val + Quote;
          end
        else if not QuotePart and ( MyChar = Delim )
        then
          begin
            // Sind noch nicht genug Zeilen da ...
            if high( FData ) < Row + 1
            then
              // ... dann auf Verdacht schon mal 10 hinzufügen
              SetLength( FData, Row + 10 );
            // Sind noch nicht genug Spalten da ...
            if high( FData[Row] ) < Col + 1
            then
              // ... dann auf Verdacht schon mal 10 hinzufügen
              SetLength( FData[Row], Col + 10 );
            // Wert eintragen
            FData[Row, Col] := Val;
            // Puffer leeren
            Val := '';
            // Spalte hochzählen
            Inc( Col );
          end
        else if not QuotePart and ( ( MyChar = #13 ) or ( MyChar = #10 ) )
        then
          begin
            // Haben wir CR LF gefunden ...
            if ( MyChar = #10 ) and ( LastChar = #13 )
            then
              begin
                // Sind noch nicht genug Zeilen da ...
                if high( FData ) < Row + 1
                then
                  // ... dann auf Verdacht schon mal 10 hinzufügen
                  SetLength( FData, Row + 10 );
                // Die Anzahl der Spalten steht jetzt fest
                SetLength( FData[Row], Col + 1 );
                // MaxCol merken
                if Col > MaxCol
                then
                  MaxCol := Col;
                // Wert eintragen
                FData[Row, Col] := Val;
                // Puffer leeren
                Val := '';
                // Zeile hochzählen
                Inc( Row );
                // Neue Zeile => erste Spalte
                Col := 0;
              end;
          end
        else
          // Das aktuelle Zeichen an den Puffer hängen
          Val := Val + MyChar;
        // Das letzte Zeichen merken
        LastChar := MyChar;
      end;

    SetLength( FData, Row );

    // Das ist eigentlich nur notwendig, wenn die CSV-Datei falsch aufgebaut ist
    // und unterschiedliche Anzahl von Spalten in den Zeilen aufweist
    // Dieses ist allerdings nicht RFC-konform, aber wir wollen mal nicht so sein
    for Row := low( FData ) to high( FData ) do
      SetLength( FData[Row], MaxCol + 1 );

  finally
    Data.Free;
  end;
end;

procedure TCSVData.SetCell( Row, Col : Integer; const Value : string );
begin
  FData[Row, Col] := Value;
end;

end.
Run Code Online (Sandbox Code Playgroud)

PS:我知道我有另一种方法使用状态模式,但我找不到它......也许以后