Delphi String替换两个字符之间的字符串
Delphi StringReplace a string between two chars
我有一个 TMemo
显示来自查询的文本。我想删除 '{'
和 '}'
之间的所有字符,所以这个字符串 '{color:black}{color}{color:black}{color}'
最终会像这样 </code>.</p>
<pre><code>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 幸运的是 offers in their RTL。
s := TRegEx.Replace('{color:black}{color}{color:black}{color}', '{.*?}', '', []);
或使用备忘录:
MemoComments.Lines.Text := TRegEx.Replace(MemoComments.Lines.Text, '{.*?}', '', []);
在此表达式中,{.*?}
、.*?
表示任意字符(.
)的任意数字(*
),但最少为可能匹配表达式的其余部分 (*?
)。最后一点非常强大。默认情况下,正则表达式是 'greedy',这意味着 .*
会匹配尽可能多的字符,所以它将把所有内容都保留到最后一个 }
,包括笑脸和所有其他字符中间的颜色代码。
Pitfalls/cons
和 Andreas 一样,我也不喜欢正则表达式。笨拙的语法很难破译,特别是如果你不经常使用它们的话。
此外,看似简单的正则表达式可能很难 执行 有时它实际上非常慢,尤其是在处理较大的字符串时。我最近遇到了一个非常神奇的东西,它在验证一个大约 1000 个字符的字符串是否与某个模式匹配时卡住了几分钟。
所使用的表达式实际上就是一个例子。它必须在 .*?
部分之后向前看,以检查它是否已经满足表达式的其余部分。如果没有,就回去,换一个角色,再往前看。对于这个表达式,这不是问题,但如果一个表达式有多个可变长度的部分,这可能是一个 CPU 密集过程!
我的早期版本 {[^}]*}
至少在理论上更有效,因为它不是 任何 字符,而是匹配所有不是 [= 的字符18=]。更容易执行,但更难阅读。在上面的答案中,我追求的是可读性而不是性能,但始终要牢记这一点。
请注意,我的第一个版本 \{[^\}]*\}
看起来更加复杂。我使用 \
来转义括号,因为它们对于分组也有特殊含义,但在这种情况下似乎没有必要。
最后,有不同的正则表达式方言,这也没有帮助。
就是这样
幸运的是 Delphi 包装了 PCRE library,它是开源的、高度优化的、维护良好的、有据可查的,并且实现了最常用的方言。
对于像这样的操作,它们可以简洁易写,使用起来足够快,如果你更频繁地使用它们,它也会变得更容易读写它们,特别是如果您使用像 regex101.com 这样的工具,您可以在其中尝试和调试正则表达式。
我有一个 TMemo
显示来自查询的文本。我想删除 '{'
和 '}'
之间的所有字符,所以这个字符串 '{color:black}{color}{color:black}{color}'
最终会像这样 </code>.</p>
<pre><code>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 幸运的是 offers in their RTL。
s := TRegEx.Replace('{color:black}{color}{color:black}{color}', '{.*?}', '', []);
或使用备忘录:
MemoComments.Lines.Text := TRegEx.Replace(MemoComments.Lines.Text, '{.*?}', '', []);
在此表达式中,{.*?}
、.*?
表示任意字符(.
)的任意数字(*
),但最少为可能匹配表达式的其余部分 (*?
)。最后一点非常强大。默认情况下,正则表达式是 'greedy',这意味着 .*
会匹配尽可能多的字符,所以它将把所有内容都保留到最后一个 }
,包括笑脸和所有其他字符中间的颜色代码。
Pitfalls/cons
和 Andreas 一样,我也不喜欢正则表达式。笨拙的语法很难破译,特别是如果你不经常使用它们的话。
此外,看似简单的正则表达式可能很难 执行 有时它实际上非常慢,尤其是在处理较大的字符串时。我最近遇到了一个非常神奇的东西,它在验证一个大约 1000 个字符的字符串是否与某个模式匹配时卡住了几分钟。
所使用的表达式实际上就是一个例子。它必须在 .*?
部分之后向前看,以检查它是否已经满足表达式的其余部分。如果没有,就回去,换一个角色,再往前看。对于这个表达式,这不是问题,但如果一个表达式有多个可变长度的部分,这可能是一个 CPU 密集过程!
我的早期版本 {[^}]*}
至少在理论上更有效,因为它不是 任何 字符,而是匹配所有不是 [= 的字符18=]。更容易执行,但更难阅读。在上面的答案中,我追求的是可读性而不是性能,但始终要牢记这一点。
请注意,我的第一个版本 \{[^\}]*\}
看起来更加复杂。我使用 \
来转义括号,因为它们对于分组也有特殊含义,但在这种情况下似乎没有必要。
最后,有不同的正则表达式方言,这也没有帮助。
就是这样
幸运的是 Delphi 包装了 PCRE library,它是开源的、高度优化的、维护良好的、有据可查的,并且实现了最常用的方言。
对于像这样的操作,它们可以简洁易写,使用起来足够快,如果你更频繁地使用它们,它也会变得更容易读写它们,特别是如果您使用像 regex101.com 这样的工具,您可以在其中尝试和调试正则表达式。