我想计算 Pascal 脚本中一个字符串在另一个字符串中出现的次数,如下例所示。
我已经看到 Delphi: count number of times a string occurs in another string 的答案,但 Pascal Script 中没有 PosEx
函数。
MyString := 'Hello World!, Hello World!, Hello World!, Hello World!';
如果我数一下Hello
或World
在这里出现的次数,结果应该是4。
如果我数一下,
(逗号)在这里出现的次数,结果应该是3。
更新
下面的函数可以工作,但是它会再次将给定的字符串复制到一个新的变量中,并删除部分字符串,因此运行速度很慢。
function OccurrencesOfSubString(S, SubStr: String): Integer;
var
DSStr: String;
begin
if Pos(SubStr, S) = 0 then
Exit
else
DSStr := S;
Repeat
if Pos(SubStr, S) <> 0 then
Inc(Result);
Delete(DSStr, Pos(SubStr, DSStr), Length(Copy(DSStr, Pos(SubStr, DSStr), Length(SubStr))));
Until Pos(SubStr, DSStr) = 0;
end;
最佳答案
您的实现通常是正确的。
需要进行一些优化并删除无用的代码:
if Pos(SubStr, S) <> 0
的第二次测试(在repeat
内)是没有意义的。这始终是真的。您正在测试S
,它已经在函数启动时进行了测试。还有DSStr
已在until
中进行了测试.- 您应该保存
Pos(SubStr, DSStr)
一个变量不要多次调用它。 -
Length(Copy(DSStr, Pos(SubStr, DSStr), Length(SubStr)))
实际上与Length(SubStr)
相同. - 无需复制
S
至DSStr
。您可以直接使用S
。它是按值参数,因此您无需修改用于调用函数的变量。 - 替换最初的
Pos(SubStr, S) = 0
在循环中使用相同的检查来保存一个Pos
打电话。
代码的优化版本:
function OccurrencesOfSubString(S, SubStr: String): Integer;
var
P: Integer;
begin
Result := 0;
repeat
P := Pos(SubStr, S);
if P > 0 then
begin
Inc(Result);
Delete(S, P, Length(SubStr));
end;
until P = 0;
end;
但实际上使用 Inno Setup StringChange
function (Delphi 没有),您不必自己编写任何算法。
function OccurrencesOfSubString(S, SubStr: String): Integer;
begin
Result := StringChange(S, SubStr, '');
end;
这是受到 @RobertFrank's answer 的启发至 Delphi: count number of times a string occurs in another string .
同时使用StringChange
看起来效率低下(因为它有显着的副作用),但实际上速度更快。可能是因为它是用 Pascal 实现的,而不是用 Pascal Script 实现的。
经过 300 万次调用测试:
OccurrencesOfSubString('Hello World!, Hello World!, Hello World!, Hello World!', 'Hello')
- 与
StringChange
:11秒 - 我的代码优化版本:49 秒
- 您的原始代码:99 秒
尽管调用很少,但所有实现都足够好。
关于inno-setup - Pascal 脚本计算一个字符串在另一个字符串中出现的次数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39907622/