Delphi字符串替换两个字符之间的字符串



我有一个TMemo,它显示查询中的文本。我想删除'{''}'之间的所有字符,这样这个字符串'{color:black}😊{color}{color:black}{color}'就会像这个😊一样结束。

MemoComments.Lines.Text :=  StringReplace(MemoComments.Lines.Text, '{'+ * +'}', '', rfReplaceAll);

我知道我的代码中的*是错误的。它只是一个占位符。我怎样才能用正确的方法来做这件事?

这可能吗?还是我必须创建一个复杂的循环?

在这种情况下,您可以使用正则表达式。我相信很快就会有人为你公布这样的答案。

然而,为了完整起见,我想证明基于循环的方法一点也不复杂,而是相当简单:

function ExtractContent(const S: string): string;
var
i, c: Integer;
InBracket: Boolean;
begin
SetLength(Result, S.Length);
InBracket := False;
c := 0;
for i := 1 to S.Length do
begin
if S[i] = '{' then
InBracket := True
else if S[i]= '}' then
InBracket := False
else if not InBracket then
begin
Inc(c);
Result[c] := S[i];
end;
end;
SetLength(Result, c);
end;

请注意,我避免了不必要的堆分配。

(就我个人而言,我从来都不是正则表达式的超级粉丝。对我来说,上述算法的正确性是显而易见的,它只能用一种方式来解释,而且它是用一种性能化的方式写的。另一方面,正则表达式有点像"魔法"。但我承认,我有点像恐龙。(

看起来您想要一种正则表达式,幸运的是Delphi在RTL中提供了这种表达式。

s := TRegEx.Replace('{color:black}😊{color}{color:black}{color}', '{.*?}', '', []);

或者使用备忘录:

MemoComments.Lines.Text := TRegEx.Replace(MemoComments.Lines.Text, '{.*?}', '', []);

在这个表达式中,{.*?}.*?表示任何字符(.(的任何数字(*(,但尽可能少以匹配表达式(*?(的其余部分。最后一点非常有力。默认情况下,正则表达式是"贪婪"的,这意味着.*将尽可能多地匹配字符,因此它将占用最后一个}之前的所有字符,包括微笑符号和其间的所有其他颜色代码。

陷阱/缺点

和Andreas一样,我也不太喜欢正则表达式。尴尬的语法可能很难解密,尤其是如果你不经常使用它们的话。

此外,一个看似简单的正则表达式可能很难执行,有时会非常慢,尤其是在处理较大字符串时。我最近遇到了一个非常神奇的,它在验证一个大约1000个字符的字符串是否符合某个模式时被卡住了好几分钟。

所使用的表达式实际上就是一个例子。它必须在.*?部分之后向前看,以检查它是否已经满足表达式的其余部分。如果没有,那就回去,换一个角色,再向前看。对于这个表达式,这不是问题,但如果一个表达式有多个可变长度的部分,这可能是一个CPU密集型的过程!

我的早期版本{[^}]*}至少在理论上更有效,因为它只匹配所有不是}的字符,而不是任何字符。更容易执行,但更难阅读。在上面的回答中,我倾向于可读性而非性能,但这始终是需要记住的。

请注意,我的第一个版本{[^}]*}看起来更加复杂。我使用来转义括号,因为它们对分组也有特殊的含义,但在这种情况下似乎没有必要。

最后,有不同的正则表达式方言,这也没有帮助。

也就是说

幸运的是,Delphi封装了PCRE库,它是开源的、高度优化的、维护良好的、文档化的,并实现了最常用的方言。

对于这样的操作,它们可以简洁易写,使用速度足够快,如果你更频繁地使用它们,读写它们也会变得更容易,尤其是如果你使用regex101.com这样的工具,你可以在那里试用和调试regex。

最新更新