Delphi 11.2如何拆分CSV字符串时忽略双引号内的逗号?
解决Delphi 11.2中CSV解析错误拆分引号内逗号的问题
我用Delphi 11.2开发,已经通过以下代码初始化了TStringList准备处理CSV:
procedure TForm2.FormCreate(Sender: TObject); begin SL := TStringList.Create; SL.Delimiter := ','; // 默认分隔符,部分地区会用";" SL.QuoteChar := '"'; // 默认引号字符 SL.StrictDelimiter := True; // 严格仅按Delimiter分隔字符串 end;
CSV示例数据:
20211605344,04/23/2021 - 09:26:42 am,4/28/2021,"Wood Drive, ENFIELD, CT","Calini, CBM",3223837, ENFIELD,Hartford,1,3,No as-built attached 20211300637,03/29/2021 - 11:48:51 am,4/1/2021,"Enfield Street, ENFIELD, CT",CBM,3223846, ENFIELD,Hartford,2,0,Job changed to aerial
尝试用以下代码将每行拆分为动态数组分配字段时,出现了错误:
procedure TForm2.Button2Click(Sender: TObject); var i:integer; TicketNumber:string; oneStr: TStringDynArray; val:double; begin SL.LoadFromFile('D:\DelphiProjects\ImportCSV\PURA Phase 2 inspection selection.csv'); for I := 1 to SL.Count-1 do begin oneStr:= SplitString(SL[i], ','); TicketNumber:= oneStr[0]; If TryStrToFloat(TicketNumber, val)then memo2.Lines.Add('TicketNo: '+oneStr[0]+' '+'Job Date: '+oneStr[1]+' '+ 'Job Start: '+oneStr[2]+' '+'Address: '+oneStr[3]+' '+ 'Crew: '+oneStr[4]+' '+'Project: '+oneStr[5]+' '+'Town: '+oneStr[6]+' '+'County: '+oneStr[7]+' '+'Order: '+oneStr[8]+' '+'Count: '+oneStr[9]+' '+'Note: '+oneStr[10]); end; end;
运行后错误拆分了双引号内的逗号,导致字段错位,输出结果:
TicketNo: 20211605344 Job Date: 04/23/2021 - 09:26:42 am Job Start: 4/28/2021 Address: "Wood Drive Crew: ENFIELD Project: CT" Town: "Calini County: CBM" Order: 3223837 Count: ENFIELD Note: Hartford TicketNo: 20211300637 Job Date: 03/29/2021 - 11:48:51 am Job Start: 4/1/2021 Address: "Enfield Street Crew: ENFIELD Project: CT" Town: CBM County: 3223846 Order: ENFIELD Count: Hartford Note: 2
问题原因
SplitString是简单的字符串拆分函数,只会按指定的分隔符拆分,完全忽略CSV格式中双引号内的逗号不作为分隔符的规则,因此导致字段错位。
正确解决方案
你已经初始化的TStringList已经配置了CSV解析所需的Delimiter、QuoteChar和StrictDelimiter属性,直接利用它的DelimitedText属性来解析每行即可,无需使用SplitString。
修改后的代码如下:
procedure TForm2.Button2Click(Sender: TObject); var i: Integer; TicketNumber: string; val: Double; LineParser: TStringList; begin SL.LoadFromFile('D:\DelphiProjects\ImportCSV\PURA Phase 2 inspection selection.csv'); // 创建临时的TStringList用于解析每行 LineParser := TStringList.Create; try LineParser.Delimiter := ','; LineParser.QuoteChar := '"'; LineParser.StrictDelimiter := True; LineParser.QuoteStrings := False; // 可选:解析后自动去掉字段的引号 for I := 0 to SL.Count - 1 do begin // 跳过空行 if Trim(SL[i]) = '' then Continue; LineParser.DelimitedText := SL[i]; TicketNumber := LineParser[0]; if TryStrToFloat(TicketNumber, val) then begin memo2.Lines.Add(Format('TicketNo: %s Job Date: %s Job Start: %s Address: %s Crew: %s Project: %s Town: %s County: %s Order: %s Count: %s Note: %s', [LineParser[0], LineParser[1], LineParser[2], LineParser[3], LineParser[4], LineParser[5], LineParser[6], LineParser[7], LineParser[8], LineParser[9], LineParser[10]])); end; end; finally LineParser.Free; end; end;
关键改动说明
- 创建临时
TStringList作为行解析器,复用CSV的格式配置; - 使用
DelimitedText属性赋值当前行,它会自动识别双引号包裹的字段,忽略内部的逗号; - 新增
QuoteStrings := False(可选),解析后自动移除字段前后的双引号,让输出更整洁; - 增加空行判断,避免处理空行导致索引越界;
- 使用
Format函数拼接字符串,代码更易读。
正确输出结果
运行修改后的代码,会得到正确的字段拆分结果:
TicketNo: 20211605344 Job Date: 04/23/2021 - 09:26:42 am Job Start: 4/28/2021 Address: Wood Drive, ENFIELD, CT Crew: Calini, CBM Project: 3223837 Town: ENFIELD County: Hartford Order: 1 Count: 3 Note: No as-built attached TicketNo: 20211300637 Job Date: 03/29/2021 - 11:48:51 am Job Start: 4/1/2021 Address: Enfield Street, ENFIELD, CT Crew: CBM Project: 3223846 Town: ENFIELD County: Hartford Order: 2 Count: 0 Note: Job changed to aerial
内容的提问来源于stack exchange,提问作者Meta Mussel
相关产品推荐
相关产品推荐

