最近、評判の良い SO ユーザーから、TStringList
CSV データの解析に失敗する分割バグがあるとの連絡を受けました。これらのバグの性質について知らされておらず、Quality Centralを含むインターネットで検索しても結果が得られなかったので、お尋ねします。TStringList 分割バグとは何ですか?
根拠のない意見に基づく回答には興味がないことに注意してください。
私が知っていること:
それほど多くはありません... 1つは、これらのバグがテストデータで表示されることはめったにありませんが、実際にはめったに表示されないということです。
もう 1 つは、前述のように、CSV の適切な解析を妨げることです。テスト データでバグを再現するのは難しいと考えて、(おそらく) 製品コードで文字列リストを CSV パーサーとして使用しようとした人に助けを求めています。
無関係の問題:
「Delphi-XE」タグ付きの質問の情報を入手したので、「スペース文字を区切り文字と見なす」 機能による解析の失敗は当てはまりません。StrictDelimiter
Delphi 2006 でのプロパティの導入により、それが解決されたためです。私自身、Delphi 2007 を使用しています。
また、文字列リストは文字列しか保持できないため、フィールドの分割のみを担当します。ロケールの違いなどに起因するフィールド値 (fi 日付、浮動小数点数など) に関連する変換の問題は対象外です。
基本的なルール:
CSV の標準仕様はありません。しかし、さまざまな仕様から推測される基本的なルールがあります。
以下は、TStringList がこれらを処理する方法のデモです。ルールと文字列の例はWikipediaからのものです。角かっこ ( [
]
) は、テスト コードによって先頭または末尾のスペース (該当する場合) を確認できるように、文字列の周りに重ねられます。
スペースはフィールドの一部と見なされるため、無視しないでください。
テスト文字列: [1997、フォード、E350] アイテム: [1997] [フォード] [E350]
コンマが埋め込まれたフィールドは、二重引用符で囲む必要があります。
テスト文字列: [1997年、フォード、E350、「スーパー、ラグジュアリー トラック」] アイテム: [1997] [フォード] [E350] [超高級トラック]
二重引用符文字が埋め込まれたフィールドは二重引用符文字で囲む必要があり、埋め込まれた二重引用符文字はそれぞれ二重引用符文字のペアで表す必要があります。
テスト文字列: [1997,Ford,E350,"Super, ""luxurious"" truck"] アイテム: [1997] [フォード] [E350] [スーパー、「豪華な」トラック]
改行が埋め込まれたフィールドは、二重引用符で囲む必要があります。
テスト文字列: [1997,Ford,E350,"Go get one now. 彼らは速く進んでいます」] アイテム: [1997] [フォード] [E350] [今すぐ入手してください。 彼らは速く進んでいます]
先頭または末尾のスペースを削除する CSV 実装では、そのようなスペースを含むフィールドを二重引用符で囲む必要があります。
テスト文字列: [1997年、フォード、E350、「スーパー ラグジュアリー トラック」] アイテム: [1997] [フォード] [E350] [超高級トラック]
フィールドは、必要かどうかに関係なく、常に二重引用符で囲むことができます。
テスト文字列: ["1997","Ford","E350"] アイテム: [1997] [フォード] [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;
すべて読んだ場合、質問は :)、「TStringList 分割バグ」とは何ですか?