1 pièce(s) jointe(s)
Utiliser l'API de la bibliothèque PCRE
Bonjour !
Je vous propose un exemple d'utilisation basique de l'API de la bibliothèque PCRE (Perl Compatible Regular Expressions). L'exemple utilise l'unité pcre_dll de Renato Mancuso.
On utilise assez rarement l'API de la bibliothèque PCRE, à cause de son caractère disons ésotérique. Voici un exemple en Pascal.
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
|
{$codepage utf8}
{$mode delphi}
uses
sysutils,
pcre_dll; { http://renatomancuso.com/software/dpcre/dpcre.htm }
type
pcre = TPcreH;
const
SUJET1 = '_27/09/2016_';
MOTIF1 = '(\d{2})/(\d{2})/(\d{4})';
CAPTURES = 3;
TAILLE_TABLEAU = 3 * (CAPTURES + 1);
var
regex: pcre;
motif: pchar;
message_erreur: pchar;
position_erreur: integer;
resultat: integer;
sujet: pchar;
tableau: array[0..TAILLE_TABLEAU - 1] of integer;
index: integer;
souschaine: ansistring;
begin
WriteLn(Format('PCRE version %s', [pcre_version()]));
motif := MOTIF1;
regex := pcre_compile(
motif,
0,
message_erreur,
position_erreur,
nil
);
if regex = nil then
begin
WriteLn(Format('La compilation de l''expression régulière a échoué. Erreur à la position %d : "%s"', [position_erreur, message_erreur]));
WriteLn(Format(' %s', [motif]));
WriteLn(Format(' %s^', [StringOfChar(' ', position_erreur)]));
end else
begin
sujet := SUJET1;
resultat := pcre_exec(
regex,
nil,
sujet,
StrLen(sujet),
0,
0,
@tableau[0],
TAILLE_TABLEAU
);
if resultat < 0 then
begin
case resultat of
PCRE_ERROR_NOMATCH:
WriteLn('Pas de correspondance trouvée.');
else
WriteLn(Format('Erreur %d.', [resultat]));
end;
end else
begin
if resultat = 0 then
begin
resultat := TAILLE_TABLEAU div 3;
WriteLn(Format('Le tableau ne peut contenir que %d sous-chaîne(s).', [resultat]));
end;
WriteLn('| index | sous-chaîne');
WriteLn('+-------+------------');
for index := 0 to resultat - 1 do
begin
souschaine := Copy(
StrPas(sujet),
tableau[2 * index] + 1,
tableau[2 * index + 1] - tableau[2 * index]
);
WriteLn(Format('| %d | "%s"', [index, souschaine]));
end;
end;
pcre_free(regex);
end;
end. |
Quelques commentaires. Les résultats de la recherche sont conservés dans un tableau de nombres entiers. Il y a deux nombres par sous-chaîne : respectivement la position (dans le sujet) du premier et du dernier caractère de la sous-chaîne. La taille du tableau est égale à trois fois fois le nombre de sous-chaînes (sous-chaîne principale et captures).
Code:
1 2 3 4 5
| const
SUJET1 = '_27/09/2016_';
MOTIF1 = '(\d{2})/(\d{2})/(\d{4})';
CAPTURES = 3;
TAILLE_TABLEAU = 3 * (CAPTURES + 1); |
Pourquoi trois fois et pas deux fois ? Parce que le dernier tiers du tableau est utilisé de façon privée par la bibliothèque, comme cela est expliqué dans la documentation.
Autre chose à remarquer, c'est qu'il y a deux étapes dans le programme : la compilation de l'expression régulière et l'exécution de la recherche. Il y a des erreurs à la compilation et des erreurs à l'exécution.
Pour provoquer une erreur de compilation dans le programme ci-dessus, remplacez le motif par un autre qui ne soit pas correct, par exemple :
Code:
1 2 3
| const
...
MOTIF1 = '[3-1]'; |
Vous obtiendrez le résultat suivant :
Code:
1 2 3 4
| PCRE version 6.7 04-Jul-2006
La compilation de l'expression régulière a échoué. Erreur à la position 3 : "range out of order in character class"
[3-1]
^ |
Concernant les erreurs d'exécution, la première chose à savoir est que l'absence de correspondance trouvée est considérée comme une erreur. Il faut donc la traiter à part.
Code:
1 2 3 4 5 6 7 8
| if resultat < 0 then
begin
case resultat of
PCRE_ERROR_NOMATCH:
WriteLn('Pas de correspondance trouvée.');
else
WriteLn(Format('Erreur %d.', [resultat]));
end; |
Autre cas à traiter en particulier : si le tableau déclaré pour contenir les résultats est trop petit, la fonction pcre_exec() renvoie la valeur 0. On peut quand même consulter les résultats mais en tenant compte du nombre de sous-chaînes disponibles.
Code:
1 2 3 4 5
| if resultat = 0 then
begin
resultat := TAILLE_TABLEAU div 3;
WriteLn(Format('Le tableau ne peut contenir que %d sous-chaîne(s).', [resultat]));
end; |
Ainsi, si vous donnez à la constante CAPTURES la valeur 2, vous obtiendrez le résultat suivant :
Code:
1 2 3 4 5 6 7
| PCRE version 6.7 04-Jul-2006
Le tableau ne peut contenir que 3 sous-chaîne(s).
| index | sous-chaîne
+-------+------------
| 0 | "27/09/2016"
| 1 | "27"
| 2 | "09" |
Quand tout se passe bien, la fonction pcre_exec() renvoie le nombre de sous-chaînes trouvées (sous-chaîne principale et captures). Il n'y a plus qu'à aller chercher la sous-chaîne dans le sujet, par exemple au moyen de la fonction Copy() :
Code:
1 2 3 4 5 6 7
| for index := 0 to resultat - 1 do
begin
souschaine := Copy(
StrPas(sujet),
tableau[2 * index] + 1,
tableau[2 * index + 1] - tableau[2 * index]
); |
Code:
1 2 3 4 5 6 7
| PCRE version 6.7 04-Jul-2006
| index | sous-chaîne
+-------+------------
| 0 | "27/09/2016"
| 1 | "27"
| 2 | "09"
| 3 | "2016" |
Ci-joint un deuxième exemple, qui montre comment rechercher les occurrences multiples d'un motif.