是否有像 PosEx 这样的 Delphi D2010 函数可以从字符串末尾开始查找字符串内的子字符串?
我正在删除对 FastStrings 库的所有调用,我使用的函数之一是 FastPosBack:
function FastPosBack(const aSourceString, aFindString : AnsiString; const aSourceLen, aFindLen, StartPos : Integer) : Integer;
我找到了 LastDelimiter,但它不完全相同,因为它只找到最后一个分隔符,而我无法指定开始位置。
谢谢!
更新:根据 DR 评论,我创建了此功能:
function FastPosBack(const aSourceString, aFindString : String; const aSourceLen, aFindLen, StartPos : Integer) : Integer;
var
RevSourceString, RevFindString: string;
begin
RevSourceString := AnsiReverseString(aSourceString);
RevFindString := AnsiReverseString(aFindString);
Result := Length(aSourceString) - PosEx(RevFindString, RevSourceString, StartPos) + 1;
end;
有没有更有效的方法?在 1000000 次循环周期中,Pos 需要 47ms,而 FastPosBack 需要 234ms 才能完成。
试试这个/这些:
function RPos(const aSubStr, aString : String; const aStartPos: Integer): Integer; overload;
var
i: Integer;
pStr: PChar;
pSub: PChar;
begin
pSub := Pointer(aSubStr);
for i := aStartPos downto 1 do
begin
pStr := @(aString[i]);
if (pStr^ = pSub^) then
begin
if CompareMem(pSub, pStr, Length(aSubStr)) then
begin
result := i;
EXIT;
end;
end;
end;
result := 0;
end;
function RPos(const aSubStr, aString : String): Integer; overload;
begin
result := RPos(aSubStr, aString, Length(aString) - Length(aSubStr) + 1);
end;
重载提供了一种调用 RPos 的方法,使用最有效的 startpos 从字符串的最末尾开始搜索,而无需自己计算。为了提高效率,在明确指定时不会对 startpos 执行检查。
在我的 SmokeTest 性能测试套件中,这比 FastPosBack 快约 20%(它顺便包含一个“相差一”错误,并且需要一些实际上并不使用的参数)。
您可以将
Pos
与 ReverseString
(来自 StrUtils)结合使用
Delphi自带了一个可以向后搜索的功能,在StrUtils单元中
SearchBuf
。不过,它专门用于搜索单词,因此它的行为可能不太符合您想要的方式。下面我将它包装成一个与您想要的接口相匹配的函数。
function FastPosBack(const aSourceString, aFindString: AnsiString;
const aSourceLen, aFindLen, StartPos: Integer): Integer;
var
Source, Match: PAnsiChar;
begin
Source := PAnsiChar(ASourceString);
Match := SearchBuf(Source, ASourceLen, ASourceLen, 0,
AFindString, [soMatchCase]);
if Assigned(Match) then
Result := Match - Source + 1
else
Result := 0;
end;
首先,考虑是否需要速度优化的解决方案。如果在实际使用中不太可能被调用 100000 次,则反转字符串并使用现有的子字符串搜索就可以了。
如果速度是一个问题,有很多好的资源可供您自己编写。在维基百科上查找“字符串搜索算法”以获取想法。当我在电脑前时,我会发布一个链接和一个示例算法。我现在正在用手机打字。
更新:
这是我承诺的例子:
function RPOS(pattern: string; text:string): Integer;
var patternPosition,
textPosition: Integer;
begin
Result := -1;
for textPosition := Length(text) downto 0 do
begin
for patternPosition := Length(pattern) downto 0 do
if not (pattern[patternPosition] = (text[textPosition - (Length(pattern) - patternPosition)])) then
break;
if patternPosition = 0 then
Result := textPosition -Length(pattern) + 1;
end;
end;
它基本上是一种反向朴素(暴力)字符串搜索算法。它从图案和文本的末尾开始,一直到开头。我可以保证它比 Delphi 的 Pos() 函数效率低,但我不能说它比 Pos()-ReverseString() 组合更快还是更慢,因为我还没有测试过它。其中有一个错误,我还没有找到原因。如果两个字符串相同,则返回 -1(未找到)。
我使用 FreePascal 的
RPOS
函数的 strutils
变体:
http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/rtl/objpas/strutils.pp?view=markup
string,string
版本与Deltics的几乎相同,但有一些变体:
Function RPosEX(C:char;const S : AnsiString;offs:cardinal):Integer; overload;<br>
Function RPosex (Const Substr : AnsiString; Const Source : AnsiString;offs:cardinal) : Integer; overload;<br>
Function RPos(c:char;const S : AnsiString):Integer; overload;<br>
Function RPos (Const Substr : AnsiString; Const Source : AnsiString) : Integer; overload;
它们是根据 FPC 的 LGPL+链接例外许可证获得许可的,但自从我编写它们以来,我特此在 BSD 许可证下发布它们。
不在标准 RTL 中,而是在 INDY 中(根据在线帮助,单位 idGlobalProtocols),这是最近 Delphi 安装的一部分:
function RPos(
const ASub: String,
const AIn: String,
AStart: Integer = -1
): Integer;
也许在搜索之前添加大写或小写的 aSubstr 和 aString 参数可以使 Deltics 的目的大小写不敏感。我认为他让你在打电话给 RPo 之前先做这件事。但也许一个可选参数可以完成这项工作。
这就是 Deltic 的目的:
function RPos(const aSubStr, aString : String; const aStartPos: Integer;
const aCaseInSensitive:boolean=true): Integer; overload;
var
i, _startPos: Integer;
pStr: PChar;
pSub: PChar;
_subStr, _string: string;
begin
if aCaseInSensitive then
begin
_subStr := lowercase( aSubstr );
_string := lowercase( aString );
end
else
begin
_subStr := aSubstr:
_string := aString;
end;
pSub := Pointer(_subStr);
if aStartPos = -1 then
_startPos := Length(_string) - Length(_subStr) + 1
else
_startPos := aStartPos;
for i := _startPos downto 1 do
begin
pStr := @(_string[i]);
if (pStr^ = pSub^) then
begin
if CompareMem(pSub, pStr, Length(_subStr)) then
begin
result := i;
EXIT;
end;
end;
end;
result := 0;
end;
function RPos(const aSubStr, aString : String;
const aCaseInSensitive:boolean=true): Integer; overload;
begin
result := RPos(aSubStr, aString, Length(aString) - Length(aSubStr) + 1,
aCaseInSensitive);
end;