如何有效地检查字符串是否包含少数子字符串之一? 假设我有一个字符串:
`Hi there, <B>my</B> name is Joe <DIV>.</DIV> Hello world. `
如何检查字符串是否包含<B>
或 <DIV>
或
?
我可以做一个简单的事情:
Result := (Pos('<B>', S) > 0) or
(Pos('<DIV>', S) > 0) or
(Pos(' ', S) > 0);
但这似乎是非常低效的,因为它使N
(在最坏的情况下)通过并且我的字符串相当大。
答案 0 :(得分:2)
这是我的解决方案,感谢David Heffernan的评论:
function StringContainsAny(const S: string; const AnyOf: array of string): Boolean;
var
CurrChr, C: PChar;
I, L, H: Integer;
begin
Result := False;
CurrChr := PChar(S);
while CurrChr^ <> #0 do
begin
H := High(AnyOf);
for I := 0 to H do
begin
L := 0;
C := PChar(AnyOf[I]);
while C^ <> #0 do
begin
if C^ = CurrChr^ then
Inc(L)
else
Break;
Inc(C);
Inc(CurrChr);
if CurrChr^ = #0 then // end of S string
begin
Result := (C^ = #0);
if Result or (not Result and (I = H)) then // match or last AnyOf
Exit;
end;
end;
if C^ = #0 then // match
begin
Result := True;
Exit;
end
else
Dec(CurrChr, L);
end;
Inc(CurrChr);
end;
end;
我不确定它是否完美。
修改强>
我能说什么?你知道他们对假设的看法......
实际测试后,似乎使用Pos()
:
function StringContainsAny(const S: string; const AnyOf: array of string): Boolean;
var
I: Integer;
begin
for I := 0 to High(AnyOf) do
begin
if Pos(AnyOf[I], S) <> 0 then
begin
Result := True;
Exit;
end;
end;
Result := False;
end;
比我的解决方案和@Green_Wizard解决方案更快!他们用Pos
功能做得很好!
答案 1 :(得分:2)
稍微好一点的版本:
function StringContainsAny(const S: string; const AnyOf: array of string): Boolean;
var
CurrChr, C: PChar;
i, j, Ln: Integer;
begin
for i := 1 to Length(S) do
begin
CurrChr := @S[i];
for j := 0 to High(AnyOf) do
begin
C := @AnyOf[j][1]; // assume that no empty strings
if C^ <> CurrChr^ then
Continue;
Ln := Length(AnyOf[j]);
if (Length(S) + 1 - i) < Ln then // check bounds
Continue;
if CompareMem(C, CurrChr, Ln * SizeOf(C^)) then
Exit(True);
end;
end;
Exit(False);
end;
您还可以构建一些停止符号表并提高速度。这是一个复杂的主题,所以我建议你阅读,例如,预订Bill Smyth "Computing Patterns in Strings"。