Delphi:StringList的分隔符始终是空格字符,即使设置了分隔符。

62

我在TStringList类中使用分隔符遇到了问题。看一下:

var
  s: string;
  sl: TStringList;

begin
  sl := TStringList.Create;
  s := 'Users^foo bar^bar foo^foobar^barfoo';
  sl.Delimiter := '^';
  sl.DelimitedText := s;
  ShowMessage(sl[1]);
end;

sl[1] 应返回 'foo bar'

sl[1] 确实返回 'foo'

看起来分隔符现在是 '^'' '

有什么想法吗?


你正在使用哪个版本的Delphi? - Roee Adler
我从来没有像现在这样因为语言错误而生气。感谢Acron让我注意到了这个问题。 - Chucky
6个回答

96
您应该设置 s1.StrictDelimiter := True 来使空格不被视为分隔符,更多信息请点击 这里
由于您使用的版本不支持上述功能(在提交答案后澄清),您有两个选择:
  1. 找到一个您知道原始文本中不会使用的字符(例如下划线),在拆分之前将所有空格转换为该字符,并在拆分后将其转换回来。这是 robosoft 的建议。
  2. 如果文本中没有引号和空格,则可以使用Alexander的技巧,在定界符之间用引号包含文本,使得'hello hello^bye bye'变成'"hello hello"^"bye bye"'。如果您选择这种方法并且它适用于您,请接受 Alexander 的答案而不是我的,他还提供了实现代码。
两种绕过不使用StrictDelimiter限制的方法都有局限性:第一种需要某些未使用的字符,而第二种需要原始文本中没有引号和空格。
也许是时候升级到更新版本的 Delphi 了 :)

1
你想绕过什么?在我看来,这似乎是一个解决方案。 - jpfollenius
4
你的起点是阅读Classes.pas中SetDelimitedText的源代码,然后要么子类化TStrings以创建一个处理字符串的版本,要么编写一个独立的函数来分割带插入符的字符串并返回一个字符串列表,使其满足你的需求。 - Todd
3
你能否暂时将空格转换成其他字符,然后在操作后再将它们改回来?使用任何在你的列表中不常出现的字符都可以。这是一种“hack”,或者我们更喜欢称之为“必要的恶作剧解决方法”。 :-) - robsoft
@Todd - 那是我在 Delphi 3 中编写的第一个重要的子类! - Gerry Coll

19
sl.DelimitedText := '"' + StringReplace(S, sl.Delimiter, '"' + sl.Delimiter + '"', [rfReplaceAll]) + '"';

3
糟糕,你赢了,我正在输入完全相同的答案 :) - The_Fox
非常聪明,谢谢亚历山大,以及The_Fox,即使你没有直接帮助我,但你的意图是这样的 :) - Acron
4
非常好,但如果原始字符串包含像“ ”(即文本中的引号和空格)这样的子段,则会出现问题。 - Roee Adler
如果原始字符串包含类似于'""'的子段,则会出现问题。而且,用户名怎么可能包含 '"' 字符呢? :) - Alex
1
@Alexander - 这是一个例子:'比尔“调情高手”克林顿' :) - Roee Adler

6

4

Delphi 7对我而言“非常好用”。这是我在采用Alexander的技巧后编写的函数:

procedure Split (const Delimiter: Char; Input: string; const Strings: TStrings) ;
begin
   Assert(Assigned(Strings)) ;
   Strings.Clear;
   Strings.Delimiter := Delimiter;
   Strings.DelimitedText :=  '"' + StringReplace(Input, Delimiter, '"' + Delimiter + '"', [rfReplaceAll]) + '"' ;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Edit1.Text := 'Users^foo bar^bar foo^foobar^barfoo';
  Split('^',Edit1.Text,Memo1.Lines);
end;

非常感谢!

2
sl.Text := StringReplace(S, sl.Delimiter, sLineBreak, [rfReplaceAll]);

1
你可能应该添加一个解释说明这段代码在做什么。 - FDinoff

0
var
  MyString: String;
  Splitted: TArray<String>;

begin
  MyString := String.Join(',', ['String1', 'String2', 'String3']);
  Splitted := MyString.Split([','], 2);
end.

选项:

Count:返回的最大拆分数;如果未指定,则默认为MaxInt。

QuoteStart/QuoteEnd:在引号包围的字符串中,开始和结束字符是被分隔符忽略的。

Options:控制是否包含任何空匹配,或者是否包含尾随空匹配。

更多信息


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接