任何内置的Delphi函数,如PosEx,从字符串的后面开始查找子字符串?

时间:2009-10-10 14:29:35

标签: delphi delphi-2009 delphi-2010

是否有像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才能完成。

7 个答案:

答案 0 :(得分:8)

您可以将PosReverseString结合使用(来自StrUtils)

答案 1 :(得分:8)

试试这个/这些:

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;

重载提供了一种使用最有效的startpos来调用RPos的方法,用于从字符串的最末端进行搜索,而无需自己计算。为了提高效率,在明确指定时不对startpos执行检查。

在我的SmokeTest性能测试套件中,它的速度比FastPosBack快20%(偶然包含“off by one”错误以及需要一些实际上没有使用的参数)。

答案 2 :(得分:3)

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;

答案 3 :(得分:2)

首先,考虑是否需要速度优化解决方案。如果不太可能在实际使用中调用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(未找到)。

答案 4 :(得分:2)

我使用Free Pascal的strutils函数中的RPOS变体:

http://svn.freepascal.org/cgi-bin/viewvc.cgi/trunk/rtl/objpas/strutils.pp?view=markup

字符串,字符串版本几乎与Deltics相同,但有变体:

Function RPosEX(C:char;const S : AnsiString;offs:cardinal):Integer; overload;
Function RPosex (Const Substr : AnsiString; Const Source : AnsiString;offs:cardinal) : Integer; overload;
Function RPos(c:char;const S : AnsiString):Integer; overload;
Function RPos (Const Substr : AnsiString; Const Source : AnsiString) : Integer; overload;

他们是FPC的LGPL +链接异常许可证,但自从我写这些许可证以来,我特此在BSD许可下发布它们。

答案 5 :(得分:1)

不在标准RTL中,而是在INDY(根据在线帮助的单元idGlobalProtocols)中,这是最近Delphi安装的一部分:

function RPos(
    const ASub: String, 
    const AIn: String, 
    AStart: Integer = -1
): Integer;

答案 6 :(得分:1)

在执行搜索之前,可能添加Uppercasing或降低aSubstr和aString参数可以使Deltics的用例不敏感。在调用RPos之前,他认为他让你这样做了。但也许一个可选的参数可以完成这项工作。

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;