9
votes

Toute fonction Delphi Build-in comme POSEX qui trouve une sous-chaîne à partir du dos de la chaîne?

Y a-t-il une fonction Delphi D2010 comme POSEX qui trouve une sous-chaîne à l'intérieur d'une chaîne à partir de la fin de la chaîne?

Je supprime tous les appels vers la bibliothèque FastStrings et une des fonctions que j'utilisais était FASTPOSBACK: P>

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;


5 commentaires

Juste hors de curiosité: comment votre test a-t-il ressemblé exactement?


J'appelle Gettickcount, suivi d'une boucle 1000000 de l'appel à la fonction, puis obtenez la différence, gettickcount - TickCount.


J'étais plus intéressé par les cordes que vous passez aux fonctions de test ...


Pour les sources "dfkfkl% & / s" # <. 676505 "et pour la recherchetring" # <". Jolies petites chaînes à rechercher.


Je ne pense pas que toute fonction qui copie la chaîne entière puisse être considérée comme "rapide"


7 Réponses :


8
votes

Vous pouvez utiliser POS en combinaison avec ReverSestring (de StrUtils)


1 commentaires

Merci pour votre réponse, en utilisant vos astuces, j'ai créé une fonction étonnamment rapide par rapport aux autres alternatives jusqu'à présent.



1
votes

pas dans le RTL standard mais dans Indy (unité IDGLOBALProtocols selon l'aide en ligne), qui fait partie des installations récentes Delphes: xxx


1 commentaires

Merci pour la réponse. Cette fonction est bien plus lente que celle que j'ai proposée, il a fallu 5913ms (RPOS) contre 234 ms à compléter.



3
votes

Delphi est livré avec une fonction pouvant rechercher en arrière, Searchbuf code > dans l'unité Strutils. Il est spécialisé pour la recherche de mots, cependant, cela pourrait ne pas se comporter tout à fait comme vous le souhaitez. Ci-dessous j'ai enveloppé dans une fonction correspondant à l'interface souhaitée.

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;


1 commentaires

Merci pour la réponse Rob. Malheureusement, cette fonction est même plus lente que celle que je peux me lever, prendre 1310 ms à compléter. J'ai changé l'ansistration et Pansichar à String et Pcharner respectivement parce que c'est ce que j'essaie d'accomplir, un remplacement décent à ces fonctions d'ansistration ultra-rapides.



2
votes

Premièrement, considérez si une solution optimisée de vitesse est nécessaire. Si ce n'est pas probable que cela s'appelle 100 000 fois dans une utilisation réelle, inverser les chaînes et utiliser la recherche de sous-chaîne existante est bien.

Si la vitesse est une question, il y a beaucoup de bonnes ressources pour vous écrire. Regardez sur Wikipedia pour «String Rechercher des algorithmes» pour des idées. Je posterai un lien et un exemple d'algorithme quand je suis à un ordinateur. Je tape ceci de mon téléphone en ce moment.

mise à jour:

Voici l'exemple que j'ai promis: xxx

sa Fondamentalement, un algorithme de recherche de chaîne naïf (force brute) inversée. Cela commence à la fin du modèle et du texte et fonctionne au début. Je peux garantir que cela est moins efficace que la fonction POS () de Delphi, bien que je ne puisse pas dire si elle est plus rapide ou plus lente que la combinaison POS () - Refersestring (), car je ne l'ai pas testé. Il y a une erreur dans ce que je n'ai pas trouvé la cause de. Si les deux chaînes sont identiques, son retour -1 (non trouvé).


7 commentaires

Vous avez probablement raison, ces différences ne seront pas perceptibles à moins d'avoir un grand nombre d'itérations.


Les petites différences s'additionnent bientôt et, dans ce cas, la routine requise est si petite qu'il est logique d'optimiser puisque l'effort de le faire est négligeable et signifie que vous n'avez alors pas à vous soucier de l'utiliser dans le code critique de performance si la besoin se pose dans le futur. L'optimisation prématurée est une erreur lorsque l'effort d'optimisation est disproportionné aux gains. Dans ce cas, l'effort est minime et est donc justifié pour tout gain s'il peut être atteint sans sacrifier la facilité d'utilisation, IMHO.


Je ne suis pas d'accord. Je pense que la simplicité gagne sur la vitesse, même dans des cas triviaux. Chaque fois que vous optimisez, vous augmentez la complexité du code. La seule fois que j'ose optimise est que la solution existante s'est avérée inadéquate dans un environnement de test ou de production.


Kenneth merci pour la fonction. Je l'ai testé et monte à 453 ms contre 344 ms. La fonction Deltics est de 300% plus rapide que la mienne à 109 ms.


Je m'attendais autant. La recherche de chaîne naïve est connue pour sa simplicité, pas sa vitesse. En fait, sauf si vous ajoutez des opérations inutiles, c'est probablement l'algorithme de recherche le moins efficace. Je l'ai utilisé parce que cela n'a pris que 5 minutes environ à écrire.


Kenneth, généralement je serais d'accord avec vous, mais dans ce cas, l'optimisation n'entraîne pas sur la complication. Si quelque chose ma solution, de tous ceux proposés implémente directement le problème comme indiqué (recherchez une sous-chaîne à partir de la fin d'une autre chaîne). D'autres impliquaient de jongler les intrants et de réexprimer le problème différemment avant de nouveau à nouveau en jonglant les sorties. Que l'approche la plus directe s'est également révélée être la plus efficace était un bonus. Je dirais également que les utilisateurs de logiciels mal performants ne sont généralement pas impressionnés par la taille du code source. :)


@Kenneth: sur ma propre expérience, pas à tout moment, vous optimisez la complexité du code. Parfois, le code moins complexe fonctionne mieux que précédent. Le facteur principal est de la gravité du programmeur d'origine.



11
votes

Essayez ceci / ceci:

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;


6 commentaires

Salut. Merci pour votre fonction, c'est bien beaucoup plus rapide que celui que je peux utiliser (344 ms vs 109ms). Les paramètres supplémentaires sur la fonction utilisent de sorte que je n'ai pas besoin de modifier les appels de fonctions FastStrings et il suffit de les remplacer par mes propres fonctions.


Deltics, est votre fonction Unicode compatible? J'ai remarqué que les paramètres de fonctions de Marco sont des restaurants et j'utiliserai ce code dans D2010.


Il a été développé et testé à l'aide de Delphi 2009, donc oui, je crois que c'est unicode "sûr". Cependant, il fait suppose que la chaîne et le substr ne contiennent que les mêmes types de «charge utile» (c'est-à-dire une chaîne et des substrateurs sont UTF16 ou ANSI, etc.).


Je viens de le tester avec des personnages spécifiques Unicode et cela fonctionne bien. Je vais accepter votre réponse car elle fournit une performance comparable au POS régulier qui est plus que suffisant pour moi. Merci encore pour toutes les réponses. Vous êtes les meilleurs les gars!


Deltics, avez-vous une fonction similaire qui n'est pas sensible à la casse? Je vais ouvrir une nouvelle question pour cette question spécifique, mais vous avez peut-être déjà quelque chose.


Je ne crains pas - ce n'était pas une routine que j'avais "couchée". La question a fait appel à mon sentiment de curiosité (et j'aime trouver des solutions efficaces à de tels problèmes), j'ai donc créé la routine pour voir quel type de résultats que j'ai obtenus - ils étaient assez bons pourvoir que c'était la peine de partager. :) Retrait de la sensibilité à l'affaire rend le problème significativement plus difficile, surtout si vous recherchez une seule solution portable sur les chaînes ANSI et UNICODE, mais vous avez fait appel à cette partie de moi, donc je vais passer quelques minutes ce soir et voir jusqu'où je reçois.



2
votes

J'utilise les variantes RPOS de la fonction Strutils de Pascal libre:

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

La chaîne, la version à chaîne est presque identique à celle de Deltics ', mais il y a des variantes:

Fonction Rondex (C: Char; const S: Ansistration; offs: cardinal): Entier; Surcharge;
Fonction Rondex (const Substr: Ansistration; const Source: Ansistration; offs: cardinal): Entier; Surcharge;
Fonction RPOS (C: Char; const S: Ansistration): Entier; Surcharge;
Fonction RPOS (const Substr: Ansistration; Const Source: Ansistration): Intégrer; surcharge;

Ils sont sous licence de licence d'exception LGPL + liant LGPL + de LGPL, mais depuis que je les ai écrites, je les libère par la présente sous licence BSD.


3 commentaires

Marco, j'ai remarqué que ces fonctions prennent tous des ansistres, alors je suppose qu'ils ne sont pas compatibles Unicode dans D2009 / D2010. Savez-vous s'il y a des plans sur la fabrication de ces unicodes compatibles?


FPC travaille sur les modes de compilation Unicode. Il suivra probablement le même modèle que sur Turbo Pascal-> Delphi, à savoir que le type de la chaîne par défaut peut être sélectionné par unité. Mais le soutien linguistique de base prendra un certain temps, et pour que les bibliothèques rattraperontont plus de temps. Les substituts de substitution rendent le cas Unicode considérablement plus difficile, car la plupart des techniques de numérisation de substitution de document travaillent en avant, pas en arrière.


Je ne m'attendrais pas à rien de la production prête au cours de la prochaine année, année et demie.



1
votes

Peut-être ajouter des paramètres asubstr et astring en majusculation ou à la masse inférieure avant de faire la recherche peut faire de l'insensible à des fins de Deltics. Je pense qu'il vous a laissé faire cela avant d'appeler Ros. Mais peut-être qu'un paramètre facultatif peut faire le travail.

Voici comment Deltic's But doit regarder: P>

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;


0 commentaires