TStringList拆分错误

Ser*_*yuz 30 csv delphi tstringlist delphi-2007

最近我被一位声誉卓着的SO用户告知,它TStringList有分裂错误,导致它无法解析CSV数据.我没有被告知这些错误的性质,在互联网上搜索包括Quality Central没有产生任何结果,所以我问.什么是TStringList拆分错误

注意,我对没有根据意见​​的答案感兴趣.


我知道的:

并不多......其中一个就是,这些错误很少出现在测试数据中,但在现实世界中却很少见.

另一方面,如上所述,它们阻止了对CSV的正确解析.认为很难用测试数据重现错误,我(可能)寻求帮助,他们尝试在生产代码中使用字符串列表作为CSV解析器.

无关紧要的问题:

我获取了有关'Delphi-XE'标记问题的信息,因此由于"空格字符被视为分隔符" 功能而无法解析,因此不适用.因为StrictDelimiterDelphi 2006 引入的属性解决了这个问题.我,我自己,正在使用Delphi 2007.

此外,由于字符串列表只能包含字符串,因此它只负责拆分字段.涉及由区域差异等引起的字段值(fi日期,浮点数......)的任何转换难度都不在范围内.

基本规则:

CSV没有标准规范.但是从各种规范中可以推断出基本规则.

下面演示TStringList如何处理这些.规则和示例字符串来自维基百科.括号([ ])叠加在字符串周围,以便能够通过测试代码查看前导或尾随空格(相关).


空间被认为是一个领域的一部分,不应该被忽视.

Test string: [1997, Ford , E350]
Items: [1997] [ Ford ] [ E350]


带嵌入逗号的字段必须包含在双引号字符中.

Test string: [1997,Ford,E350,"Super, luxurious truck"]
Items: [1997] [Ford] [E350] [Super, luxurious truck]


具有嵌入式双引号字符的字段必须包含在双引号字符中,并且每个嵌入的双引号字符必须由一对双引号字符表示.

Test string: [1997,Ford,E350,"Super, ""luxurious"" truck"]
Items: [1997] [Ford] [E350] [Super, "luxurious" truck]


嵌入换行符的字段必须包含在双引号字符中.

Test string: [1997,Ford,E350,"Go get one now
they are going fast"]
Items: [1997] [Ford] [E350] [Go get one now
they are going fast]


在修剪前导或尾随空格的CSV实现中,具有此类空格的字段必须包含在双引号字符中.

Test string: [1997,Ford,E350," Super luxurious truck "]
Items: [1997] [Ford] [E350] [ Super luxurious truck ]


无论是否必要,字段可以始终包含在双引号字符中.

Test string: ["1997","Ford","E350"]
Items: [1997] [Ford] [E350]



测试代码:

var
  SL: TStringList;
  rule: string;

  function GetItemsText: string;
  var
    i: Integer;
  begin
    for i := 0 to SL.Count - 1 do
      Result := Result + '[' + SL[i] + '] ';
  end;

  procedure Test(TestStr: string);
  begin
    SL.DelimitedText := TestStr;
    Writeln(rule + sLineBreak, 'Test string: [', TestStr + ']' + sLineBreak,
            'Items: ' + GetItemsText + sLineBreak);
  end;

begin
  SL := TStringList.Create;
  SL.Delimiter := ',';        // default, but ";" is used with some locales
  SL.QuoteChar := '"';        // default
  SL.StrictDelimiter := True; // required: strings are separated *only* by Delimiter

  rule := 'Spaces are considered part of a field and should not be ignored.';
  Test('1997, Ford , E350');

  rule := 'Fields with embedded commas must be enclosed within double-quote characters.';
  Test('1997,Ford,E350,"Super, luxurious truck"');

  rule := 'Fields with embedded double-quote characters must be enclosed within double-quote characters, and each of the embedded double-quote characters must be represented by a pair of double-quote characters.';
  Test('1997,Ford,E350,"Super, ""luxurious"" truck"');

  rule := 'Fields with embedded line breaks must be enclosed within double-quote characters.';
  Test('1997,Ford,E350,"Go get one now'#10#13'they are going fast"');

  rule := 'In CSV implementations that trim leading or trailing spaces, fields with such spaces must be enclosed within double-quote characters.';
  Test('1997,Ford,E350," Super luxurious truck "');

  rule := 'Fields may always be enclosed within double-quote characters, whether necessary or not.';
  Test('"1997","Ford","E350"');

  SL.Free;
end;
Run Code Online (Sandbox Code Playgroud)



如果您已经阅读了所有内容,问题是:),什么是"TStringList拆分错误?"

Cos*_*und 13

并不多......其中一个就是,这些错误很少出现在测试数据中,但在现实世界中却很少见.

所需要的只是一个案例.测试数据不是随机数据,一个用户有一个失败案例应该提交数据并且我们有一个测试用例.如果没人能提供测试数据,可能没有错误/失败?

CSV没有标准规范.

那个确定有助于混乱.没有标准规范,你如何证明出错?如果这是出于自己的直觉,你可能会遇到各种各样的麻烦.这里有一些来自我自己与政府发行的软件的快乐互动; 我的应用程序应该以CSV格式导出数据,政府应用程序应该导入它.这里是什么让我们陷入一个很大的麻烦几年连续:

  • 你如何表示空数据?由于没有CSV标准,一年我友好的政府决定采取任何行动,包括一切(连续两个逗号).接下来他们决定只有连续的逗号是可以的,也就是说,Field,"",Field是无效的,应该是Field,,Field.有很多乐趣向我的客户解释gov应用程序将验证规则从一周更改为下一周......
  • 你导出ZERO整数数据吗?这可能是一个更大的滥用,但我的"政府应用程序"决定也验证.曾经强制要求包括0,然后强制要求不包括0.也就是说,有一次Field,0,Field是有效的,接下来Field,,Field是唯一有效的方式......

这是另一个测试案例,其中(我的)直觉失败了:

1997年,福特,E350,"超级豪华卡车"

请注意之间的空间,,并"Super和随后的很幸运逗号"Super.TStrings如果它紧跟在分隔符之后,那么所使用的解析器只能看到引号char .该字符串被解析为:

[1997]
[ Ford]
[ E350]
[ "Super]
[ luxurious truck"]
Run Code Online (Sandbox Code Playgroud)

直觉我期望:

[1997]
[ Ford]
[ E350]
[Super luxurious truck]
Run Code Online (Sandbox Code Playgroud)

但是猜猜看,Excel的做法与Delphi的做法相同......

结论

  • TStrings.CommaText相当不错并且实现得很好,至少我看过的Delphi 2010版本是非常有效的(避免多个字符串分配,使用a PChar来"解析"解析后的字符串)并且与Excel的解析器的工作方式大致相同.
  • 在现实世界中,您需要与其他软件交换数据,使用其他库(或根本没有库)编写,人们可能会错过解释CSV的一些(缺失的?)规则.你必须适应,它可能不是一个对错的情况,而是一个"我的客户需要导入这个废话"的情况.如果发生这种情况,您将必须编写自己的解析器,该解析器适应您要处理的第三方应用程序的要求.在此之前,您可以放心使用TStrings.当它确实发生时,它可能不是TString错!