9

文字列の末尾から始まる文字列内の部分文字列を見つける PosEx のような Delphi D2010 関数はありますか?

FastStrings ライブラリへのすべての呼び出しを削除しています。使用していた関数の 1 つは 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 は 47 ミリ秒、FastPosBack は 234 ミリ秒で完了します。

4

7 に答える 7

11

これ/これらを試してください:

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" エラーが含まれており、実際には使用しないいくつかのパラメーターが必要です)。

于 2009-10-10T22:44:01.733 に答える
8

(StrUtilsから)Posと組み合わせて使用​​できますReverseString

于 2009-10-10T14:32:32.297 に答える
3

SearchBufDelphi には、StrUtils ユニットで後方検索できる関数が付属しています。ただし、単語の検索に特化しているため、意図したとおりに動作しない場合があります。以下では、目的のインターフェイスに一致する関数にラップしました。

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;
于 2009-10-10T15:57:25.760 に答える
2

FreePascalの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+linking例外ライセンスの下でライセンスされていますが、私がそれらを書いたので、私はここにBSDライセンスの下でそれらをリリースします。

于 2009-10-11T17:28:44.103 に答える
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() の組み合わせよりも速いか遅いかはわかりません。原因がわからないエラーがあります。2 つの文字列が同一の場合、-1 が返されます (見つかりません)。

于 2009-10-10T16:04:59.537 に答える
1

標準のRTLではなく、最近のDelphiインストールの一部であるINDY(オンラインヘルプによるとユニットidGlobalProtocols)にあります。

function RPos(
    const ASub: String, 
    const AIn: String, 
    AStart: Integer = -1
): Integer;
于 2009-10-10T15:47:26.093 に答える
1

おそらく、検索を行う前に 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;
于 2011-08-04T01:49:49.033 に答える