【问题标题】:Delphi Tstringlist, get strings as a quoted, comma delimited string?Delphi Tstringlist,将字符串作为带引号的逗号分隔字符串?
【发布时间】:2015-11-18 12:27:37
【问题描述】:

我有一个包含在数据库表中使用的键列表的 Tstringlist。 我想要一种简单的方法来生成一个包含所有键的字符串,每个键用逗号分隔并用单引号括起来。 这样它就可以在 SQL 'IN' 语句中使用 例如WHERE FieldX IN ('One','Two','Three').

我尝试过使用quotechar,但在阅读 commatext 时它会被忽略。 比如下面的代码

procedure junk;
var
  SL : Tstringlist;
  s : string;
begin
 SL := Tstringlist.Create;
 SL.Delimiter :=','; //comma delimiter
 SL.QuoteChar := ''''; //single quote around strings
 SL.Add('One');
 SL.Add('Two');
 SL.Add('Three');
 try
   s :=  SL.commatext;
   showmessage(s);
 finally
   SL.Free;
 end; //finally
end; //junk

显示消息 One,Two,Three - 不带任何引号。

我知道我可以做到这一点,就像在

procedure junk;
var
  SL : Tstringlist;
  s : string;
  i : integer;
begin
 SL := Tstringlist.Create;
 SL.Delimiter :=','; //comma delimiter
 SL.Add('One');
 SL.Add('Two');
 SL.Add('Three');
 try
 s := '';
 for I := 0 to SL.Count - 1 do
    begin
    s := s +  ',' + '''' + SL[i] + '''';
    end;
 delete(s,1,1);
 showmessage(s);
 finally
   SL.Free;
 end;//finally
end;

但是有没有更简单的方法使用 Tstringlist 本身的属性?

【问题讨论】:

  • 您这样做的尝试是不够的,因为您没有转义引号字符

标签: delphi csv tstringlist


【解决方案1】:

如果您使用的是 D2006 或更高版本,则可以使用 CLASS HELPER:

USES Classes,StrUtils;

TYPE
  TStringListHelper = CLASS HELPER FOR TStrings
                        FUNCTION ToSQL : STRING;
                      END;

FUNCTION TStringListHelper.ToSQL : STRING;
  VAR
    S : STRING;

  FUNCTION QuotedStr(CONST S : STRING) : STRING;
    BEGIN
      Result:=''''+ReplaceStr(S,'''','''''')+''''
    END;

  BEGIN
    Result:='';
    FOR S IN Self DO BEGIN
      IF Result='' THEN Result:='(' ELSE Result:=Result+',';
      Result:=Result+QuotedStr(S)
    END;
    IF Result<>'' THEN Result:=Result+')'
  END;

这段代码:

SL:=TStringList.Create;
SL.Add('One');
SL.Add('Two');
SL.Add('Number Three');
SL.Add('It''s number 4');
WRITELN('SELECT * FROM TABLE WHERE FIELD IN '+SL.ToSQL);

然后会输出:

SELECT * FROM TABLE WHERE FIELD IN ('One','Two','Number Three','It''s number 4')

【讨论】:

  • 有用的答案。我已经完全按照您的建议编写了整个单元的辅助函数,可以执行 ToSQL.text、ToSQL.date 等以及相反的操作,例如 FromDB.date、FromSQL.time 等,以便使用德尔福变量。本质上,您是在建议它只是将我的“长路”代码以打包形式放在该单元内。整洁的好主意,但并没有真正回答我关于 Tstringlist 是否可以自己完成的实际问题
  • 它不能——但是通过使用 CLASS HELPER,你可以让它看起来像可以 :-)
  • 我想我会接受你的回答,部分原因是你实际上已经回答了这个问题 - 尽管说它无法完成 部分是因为按照你的建议做并且把我的'long另一个辅助函数中的“方式”代码确实使它看起来像是在做这项工作的 Tstringlist。
【解决方案2】:

使用sl.DelimitedText 而不是sl.CommaText 使其符合您的设置。 CommaText 将暂时将 DelimiterQuoteChar 更改为一些硬编码值。

【讨论】:

  • 我已经尝试过了,没有区别,它仍然显示为 One,Two,Three 并且值周围没有单引号。
  • @user3209752:这可能是因为不需要引用字符串,因为其中没有空格或逗号。尝试使用包含逗号和/或空格的值...
  • 但我需要在最后的逗号分隔字符串中引用它们,否则使用该字符串的 SQL 会将它们解释为列名而不是字符串文字。即FieldX IN(一,二,三)与FieldX IN('一','二','三')非常不同
  • 文档实际上支持您:When retrieving DelimitedText, the resulting value delimits individual strings in two ways: each string is surrounded (before and after) by the quotation marks character specified by the QuoteChar property. In addition, individual strings are separated by the character specified by the Delimiter property.。它只是不执行第一部分中所述的操作(至少不是针对单个单词字符串)
【解决方案3】:

不能依赖 CommaText(显然还有 DelimitedText)来添加引号,因为它们对单个单词和多单词字符串的处理方式不同。

检索 CommaText 时,列表中包含空格的任何字符串, 逗号或引号将包含在双引号中,并且任何双引号 字符串中的引号将被重复。

单独使用 TStringList 似乎没有任何组合,因此我建议您使用 QuotedStr 添加字符串。 无论字符串是单个单词还是多个单词,以下设置都可以按照您的意愿工作:

 SL := Tstringlist.Create;
 SL.Delimiter :=','; //comma delimiter
 SL.StrictDelimiter := True;
// SL.QuoteChar := ''''; //single quote around strings
// SL.Add('One');
// SL.Add('Two words');
// SL.Add('Three');
 SL.Add(QuotedStr('One'));
 SL.Add(QuotedStr('Two words'));
 SL.Add(QuotedStr('Three'));
 s := SL.CommaText; // or SL.DelimitedText;
 showmessage(s);

输出是:

'一个','两个字','三个'

【讨论】:

  • StrictDelimiter 不会做你可能想知道的事情
  • @fantaghirocco 哦?那可能是什么?
  • 是我的测试之一:您尝试过您的代码吗?它没有按预期打印引号。似乎没有一个简单的方法......
  • @fantaghirocco 正如你在最后一行看到的。但重读后,我关于 CommaText 的第一个声明并没有按预期完成。谢谢
  • 在我的最后一条评论中,我没有注意到QuotedStr 的使用:显然它打印了预期的内容。我很抱歉 O:-)
【解决方案4】:

TStrings.DelimitedText 方法仅在需要时引用字符串:当有链接 O'ne 时,这将打印为 'O''ne' - 即双引号。

您可以实现您想要的设置便利分隔符和QuoteChar 属性为#0 值,然后用引号替换分隔符。

procedure junk;
var
  sl : Tstringlist;
  s: string;
begin
  sl := Tstringlist.Create;
  try
    sl.Delimiter := '|';
    sl.QuoteChar := #0;//no quote
    sl.Add('On''e');
    sl.Add('Two');
    sl.Add('Three');

    //escape the single quotes
    s := StringReplace(sl.DelimitedText, '''', '''''', [rfReplaceAll]);

    //replace the delimiters and quote the text
    s := '''' +  StringReplace(s, sl.Delimiter, ''',''', [rfReplaceAll]) + '''';

    WriteLn(s);

  finally
    sl.Free;
  end;
end;

【讨论】:

  • 这比我的“长路”还要复杂!您正在通过输入字符串中的定界符告诉字符串列表期望什么,我不能这样做,因为输入是在没有定界符的其他地方生成的,而且您明确地在每个字符串周围加上引号,出于同样的原因,我不能这样做。我无法更改字符串列表首先包含的内容。看起来我的“漫长道路”的变体将成为唯一的道路
  • sl 对象的字符串永远不会改变。即使在列表中填充了值之后,您也可以分配 DelimiterQuoteChar。这仅影响DelimitedText 输出
【解决方案5】:

我已经解决了类似的问题:

  s := ''' + StringReplace(sl.CommaText, ',', ''',''', [rfReplaceAll]) + '''

【讨论】:

  • 如果字符串列表中的条目之一包含逗号...或者如果其中一个条目包含单引号...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-16
  • 1970-01-01
  • 1970-01-01
  • 2017-01-05
  • 2022-06-11
  • 1970-01-01
相关资源
最近更新 更多