在Delphi中读取包含多行记录的CSV文件

时间:2010-05-14 01:22:08

标签: delphi csv

通常我只使用TStringList.CommaText,但是当给定字段有多行时,这不起作用。基本上我需要一个符合rfc4180的csv处理器。我宁愿不必自己实现RFC。

3 个答案:

答案 0 :(得分:1)

您真的需要完整的RFC支持吗?我无法计算我在perl或类似内容中编写“csv解析器”的次数。在逗号上拆分并完成。唯一的问题是当你需要尊重报价时。如果你这样做,写一个“quotesplit”例程来查找引号并确保它们是平衡的。除非这个csv处理器是某些应用程序的肉和土豆,否则我不确定它真的会成为一个问题。

另一方面,我真的不认为完全实现rfc是那么复杂。与HTTP,SMTP,IMAP等相比,这是一个相对较短的rfc。

在perl中,我写的一个不错的quotesplit()是:

sub quotesplit {
    my ($regex, $s, $maxsplits) = @_;
    my @split;
    my $quotes = "\"'";
    die("usage: quotesplit(qr/.../,'string...'), // instead of qr//?\n")
        if scalar(@_) < 2;

    my $lastpos;
    while (1) {
        my $pos = pos($s);

        while ($s =~ m/($regex|(?<!\\)[$quotes])/g) {
            if ($1 =~ m/[$quotes]/) {
                $s =~ m/[^$quotes]*/g;
                $s =~ m/(?<!\\)[$quotes]/g;
            }
            else {
                push @split, substr($s,$pos,pos($s) - $pos - length($1));
                last;
            }
        }

        if (defined(pos($s)) and $lastpos > pos($s)) {
            errorf('quotesplit() issue: lastpos %s > pos %s',
                $lastpos, pos($s)
            );
            exit;
        }
        if ((defined($maxsplits) && scalar(@split) == ($maxsplits - 1))) {
            push @split, substr($s,pos($s));
            last;
        }
        elsif (not defined(pos($s))) {
            push @split, substr($s,$lastpos);
            last;
        }

        $lastpos = pos($s);
    }

    return @split;
}

答案 1 :(得分:0)

你试过使用Delimiter:=';'和DelimiterText:=而不是CommaText?

顺便说一下,R​​FC完全没有意义......在CSV上请求评论是荒谬的......

答案 2 :(得分:0)

这是我的CSV解析器(可能不是RFC,但它可以正常工作)。每次为您提供下一个CSV字段时,请继续在提供的字符串上调用它。我不相信它有多行问题。

function CSVFieldToStr(
           var AStr : string;
               ADelimChar : char = Comma ) : string;
{ Returns the next CSV field str from AStr, deleting it from AStr,
  with delimiter }
var
  bHasQuotes : boolean;

  function HandleQuotes( const AStr : string ) : string;
  begin
    Result := Trim(AStr);
    If bHasQuotes then
      begin
      Result := StripQuotes( Result );
      ReplaceAllSubStrs( '""', '"', Result );
      end;
  end;

var
  bInQuote    : boolean;
  I           : integer;
  C           : char;
begin
  bInQuote   := False;
  bHasQuotes := False;
  For I := 1 to Length( AStr ) do
    begin
    C := AStr[I];
    If C = '"' then
      begin
      bHasQuotes := True;
      bInQuote := not bInQuote;
      end
     else
      If not bInQuote then
       If C = ADelimChar then
          begin
          Result := HandleQuotes( Copy( AStr, 1, I-1 ));
          AStr   := Trim(Copy( AStr, I+1, MaxStrLEn ));
          Exit;
          end;
    end;
  Result := HandleQuotes(AStr);
  AStr := '';
end;