2016-10-22 4 views
1

J'ai besoin d'extraire une sous-chaîne après un délimiteur spécifique, mais si le délimiteur spécifié est entre deux autres balises, il doit être ignoré.Comment extraire une sous-chaîne après le délimiteur, mais ignorer si elle se trouve entre deux balises?

Par exemple, prenez cette chaîne de test:

Le < rapide "fox @brown"> saute par-dessus le chien paresseux. Le rapide @renard brun saute par-dessus le chien paresseux

La sortie souhaitée serait:

saute renard brun sur le chien paresseux

En effet, le Le premier @ délimiteur trouvé est entre deux "" et devrait donc être ignoré, le second @ délimiteur n'est pas à l'intérieur de "" et donc le texte devrait être extrait.

Je suis en mesure de trouver la position de départ du delimiter @ en utilisant Pos et extraire le texte à droite de celui-ci, comme indiqué ci-dessous:

procedure TForm1.Button1Click(Sender: TObject); 
var 
    S: string; 
    I: Integer; 
begin 
    S := 'The quick <"@brown fox"> jumps over the lazy dog. The quick @brown fox jumps over the lazy dog'; 
    I := Pos('@', S); 
    if I > 0 then 
    begin 
    ShowMessage(Copy(S, I, Length(S))); 
    end; 
end; 

Cependant, cela trouvera toujours le premier delimiter @ peu importe si il est entouré de deux "" ou non. Le résultat de ce qui précède est:

fox @brown "> saute par-dessus le chien paresseux Le rapide @renard brun saute par-dessus le chien paresseux

où le résultat souhaité devrait être.:

renard brun saute par dessus le chien paresseux

Comment puis-je modifier le code pour ignorer @ délimiteurs lors de l'utilisation Pos si le délimiteur est entre deux "" balises? Je veux seulement trouver le premier @ délimiteur et copier le texte après.

Il a également peu importe s'il y a d'autres @ délimiteurs après la première valide est trouvé, par exemple, cela devrait aussi être valable:

Le < rapide « fox @brown »> saute par-dessus la chien paresseux. Le rapide @renard brun saute @ ov @ er le chien paresseux @

devrait revenir encore:

renard brun saute par-dessus le chien paresseux

Parce que nous sont seulement intéressés par le premier délimiteur @ valide, en ignorant tout le reste après et en ignorant quoi que ce soit entre deux "" balises.

S'il vous plaît noter bien que j'ai marqué Delphi je ne l'utilise principalement Lazare donc idéalement, je aurais besoin d'aide à venir avec une solution qui n'utilise pas d'aide magique avec des aides à cordes etc.

Merci.

Répondre

1

Pour savoir si le @ est pas dans " balises enserrant, analyser la chaîne depuis le début.

Si un délimiteur est trouvé après une balise d'ouverture, mais qu'il n'y a pas de balise de fermeture, cette routine extraira également le résultat.

function ExtractString(const s: String): String; 
var 
    tagOpen: Boolean; 
    delimiterPos,i,j: Integer; 
begin 
    tagOpen := false; 
    delimiterPos := 0; 
    Result := ''; 
    for i := 1 to Length(s) do begin 
    if (s[i] = '"') then begin 
     tagOpen := not tagOpen; 
     delimiterPos := 0; 
    end 
    else begin 
     if (s[i] = '@') then begin 
     if (delimiterPos = 0) then 
      delimiterPos := i; 
     if not tagOpen then // Found answer 
      Break; 
     end; 
    end;   
    end; 

    // If there is no closing tag and a delimiter is found 
    // since the last opening tag, deliver a result. 
    if (delimiterPos > 0) then begin 
    // Finally extract the string and remove all `@` delimiters. 
    SetLength(Result,Length(s)-delimiterPos); 
    j := 0; 
    for i := 1 to Length(Result) do begin 
     Inc(delimiterPos); 
     if (s[delimiterPos] <> '@') then begin 
     Inc(j); 
     Result[j] := s[delimiterPos]; 
     end; 
    end; 
    SetLength(Result,j);  
    end; 
end; 
+0

brillants, et merci pour ajouter dans les commentaires aussi :) – Craig

0
procedure TForm1.Button1Click(Sender: TObject); 
var 
    S: string; 
    L, I: Integer; 
    take : Boolean; 
begin 
    S := 'The quick <"@brown fox"> jumps over the lazy dog. The quick @brown fox jumps over the lazy dog'; 
    L := Length(S); 
    I := Pos('@', S); 

    while I > 0 do 
    begin 
    take := True; 
    if I > 1 then take := S[I-1] <> '"'; 
    if take then begin 
     if I < L then 
     ShowMessage(Copy(S, I + 1, L)); 
     Break; 
    end; 
    S[I] := '_'; 
    I := Pos('@', S); 
    end; 
end; 
+1

ne fonctionne pas si la balise d'ouverture '" 'est plus d'une position avant' '@, ou est la balise de fermeture. –