K3. Utilisation des métacaractères |
Page d'accueil Précédent Suivant |
Antislash (\) Le caractère antislash a de nombreuses fonctions. En premier lieu, s'il est suivi d'un caractère non alpha-numérique, il ne prendra pas la signification spéciale qui y est rattachée. Cette utilisation de l'antislash comme caractère d'échappement s'applique à l'intérieur et à l'extérieur des classes de caractères. Par exemple, pour rechercher le caractère étoile " * ", il faut écrire dans le masque : " \* ". Cela s'applique dans tous les cas, que le caractère qui suive soit un métacaractère ou non. C'est un moyen sûr pour s'assurer qu'un caractère sera recherché pour sa valeur littérale, plutôt que pour sa valeur spéciale. En particulier, pour rechercher les antislash, il faut écrire : " \\ ". Si un masque est utilisé avec l'option PCRE_EXTENDED , les espaces blancs du masque, mais qui ne sont pas dans une classe de caractères, et les caractères entre dièses " # ", ainsi que les nouvelles lignes sont ignorés. L'antislash peut être utilisé pour échapper et ainsi rechercher un espace ou un dièse. Si vous voulez désactiver la valeur spécifique de la séquence de caractères, mettez-la entre \Q et \E. La séquence \Q...\E fonctionne à l'intérieur et à l'extérieur des classes de caractères. Caractères invisibles La deuxième utilité de l'antislash est de pouvoir coder des caractères invisibles dans les masques. Il n'y a pas de restriction sur la place de ces caractères invisibles, hormis pour le caractère nul qui doit terminer le masque. Dans le cas où le masque est créé avec un éditeur de texte, il est plus facile d'utiliser une séquence d'échappement plutôt que le caractère binaire qu'elle représente :
Dans la séquence " \cx ", si " x " est en minuscule, il est converti en majuscule. Puis, le bit 6 (hex 40) est inversé. Ainsi " \cz " devient 1A , mais " \c{ " devient hex 3B, tandis que " \c; " devient hex 7B. Après " \x ", deux caractères hexadécimaux sont lus (les lettres peuvent être en majuscule ou en minuscule). Après " \0 ", deux caractères octal sont lus. Dans chacun des cas, le métacaractère tente de lire autant de caractères que possible. Ainsi la séquence " \0\x\07 ", sera comprise comme deux caractères nuls, suivi d'un caractère alarme (BEL), code 7. Dans le cas où vous utilisez le système de numération octal, assurez-vous que vous fournissez deux chiffres significatifs après le nul initial. La gestion de la séquence " \y ", avec y <> 0 est plutôt compliquée. En dehors des caractères de classes, PCRE va lire "y" et tous les caractères qui suivent comme des chiffres décimaux. Si "y" est plus petit que 10, ou bien s'il y a déjà eu au moins autant de parenthèses ouvrantes auparavant, la séquence est prise pour une référence arrière. A l'intérieur d'un caractère de classe, ou si "y" est plus grand que 9, et qu'il n'y a pas eu assez de parenthèses ouvrantes auparavant, PCRE lit jusqu'à 3 chiffres octals à la suite de l'antislash et génère un octet unique, à partir des 8 bits de poids faible de la séquence. Tous les chiffres qui suivent ne sont pas interprétés, et se représentent eux-mêmes. Par exemple
Les valeurs octales supérieures ou égales à 100 ne doivent pas être introduites par un 0, car seuls les trois premiers octets seront lus. Toutes les séquences qui définissent une valeur d'un seul octet peuvent être utilisées dans les classes de caractères et à l'extérieur. De plus, dans une classe de caractères, la séquence " \b " est interprétée comme un caractère effacer (backspace, hex 08) ; la séquence \X comme caractère "X". A l'extérieur de la classe de caractères, les séquences peuvent avoir d'autres significations. Types de caractères génériques On peut encore se servir de l'antislash pour préciser des types génériques de valeurs. Les types listés ci-dessous sont toujours reconnus :
Chaque paire précédente définit une partition de la table des caractères : les deux ensembles sont disjoints. Un caractère satisfera soit un ensemble, soit l'autre. Ces séquences de caractères peuvent apparaître à l'intérieur ou à l'extérieur des classes de caractères. Elles remplacent à chaque fois un caractère de type correspondant. Si cette séquence est placée en fin de masque, et qu'il n'y a plus de caractère à comparer dans la chaîne sujet, la recherche échoue. \s ne correspond pas au caractère VT (code 11). C'est ce qui fait la différence par rapport à la classe "espace" dans POSIX. Les caractères \s sont HT (9), LF (10), FF (12), CR (13) et espace (32). Assertions simples La quatrième utilisation de l'antislash intervient lors d'assertions simples. Une assertion impose une condition à un certain point, sans remplacer de caractère. L'utilisation de sous-masques pour réaliser des assertions plus complexes est décrite plus-bas. Les assertions avec antislash sont les suivantes :
Ces assertions ne peuvent pas apparaître dans une classe de caractères (mais "\b" a une autre signification à l'intérieur d'une classe de caractères) – caractère de retour (backspace)). Accent circonflexe (^) et Dollar ($) En dehors d'une classe de caractères, avec les options par défaut, ^ est une assertion qui n'est vraie que si elle est placée au tout début de la chaîne. A l'intérieur d'une classe de caractères, ^ a un tout autre sens (voir ci-dessous). Le métacaractère ^ n'a pas besoin d'être le premier caractère du masque, si plusieurs alternatives sont proposées, mais il doit être placé en premier dans chaque alternative. Si toutes les alternatives commencent par ^ , alors le masque est dit ancré (il y a une autre construction qui porte cette appellation). Le métacaractère $ est une assertion qui n'est vraie que si elle est placée tout en fin de chaîne ou juste avant un caractère de nouvelle ligne qui serait le dernier caractère de la chaîne (par défaut). $ n'a pas besoin d'être le dernier caractère du masque, si plusieurs alternatives sont proposées, mais il doit être placé en dernier dans chaque alternative. $ n'a pas de valeur particulière dans la classe de caractères. La signification de $ peut changer, de manière à l'amener à ce qu'il ne puisse se trouver qu'en toute fin de la chaîne sujet. Cela se fait en ajoutant l'option PCRE_DOLLAR_ENDONLY au moment de la compilation, ou de l'exécution. Cette option est inopérante sur \Z . La signification de ^ et de $ peuvent changer si l'option PCRE_MULTILINE est activée. Dans ce cas, outre la comparaison au début et à la fin de la chaîne sujet, ils sont mis en comparaison immédiatement avant et immédiatement après un caractère interne de nouvelle ligne. Par exemple, le masque /^abc$/ accepte la chaîne " def\nabc " uniquement en mode multi-lignes ( \n - caractère de saut de ligne). Par conséquent, toutes les parties du masques qui commencent par " ^ " ne sont pas ancrées, en mode multi-lignes. Ainsi, la comparaison avec ^ est possible en cas de déplacement initial non nul de l'argument de la fonction pcre_exec(). Point En dehors d'une classe de caractères, un point remplace n'importe quel caractère, même invisible et à l'exception (par défaut) du caractère de nouvelle ligne. La gestion des points est complètement indépendante de ^ et $ . Le seul point commun est que les deux ont un comportement particulier vis-à-vis des caractères de nouvelle ligne. Le point n'a pas de comportement particulier dans la classe de caractères. Crochets et classes de caractères Un crochet ouvrant [ introduit une classe de caractères, et le crochet fermant ] la conclut. Le crochet fermant n'a pas de signification en lui-même. Si le crochet fermant est nécessaire à l'intérieur d'une classe de caractères, il faut qu'il soit le premier caractère (après un ^ éventuel) ou échappé avec un antislash. Une classe de caractère correspond à un seul caractère dans le texte. Une classe de caractères remplace un seul caractère dans la chaîne sujet, à moins que le premier caractère de la classe soit un accent circonflexe ^ , qui représente une négation : le caractère ne doit pas se trouver dans la classe. Si ^ est nécessaire dans la classe, il suffit qu'il ne soit pas le premier caractère, ou bien qu'il soit échappé avec un antislash. Par exemple, le caractère [aeiou] remplace n'importe quelle voyelle minuscule, tandis que [^aeiou] remplace n'importe quel caractère qui n'est pas une voyelle minuscule. Il est à noter que l'accent circonflexe sert seulement à spécifier des carcactères qui ne sont pas dans la classe en facilitant ainsi l'indication des caractères au sein de la classe. La classe commençant par un accent circonflexe n'est pas une assertion : une telle classe nécessite un caractère depuis le texte, au cas où l'indicateur courant est placé à la fin de la ligne, la comparaison avec le masque ne se fait pas. En cas de comparaison insensible à la casse, tous les caractères dans la classe représentent en même temps les versions minuscules et les versions majuscules. Le signe moins ( - ) est utilisé pour spécifier un intervalle de caractères, dans une classe. Par exemple, [d-m] remplace toutes les lettres entre d et m inclus. Si le caractère moins est requis dans une classe, il faut l'échapper avec un antislash, ou le faire apparaître à une position ou il ne pourra pas être interprété comme une indication d'intervalle, c'est-à-dire au début ou à la fin de la classe. Il n'est pas possible d'avoir le caractère crochet fermant " ] " comme fin d'intervalle. Un masque tel que [W-]46] est compris comme la classe de caractères contenant deux caractères ("W" et "-") suivie de la chaîne littérale "46]", ce qui fait qu'il va accepter " W46] " ou " -46] ". Cependant, si " ] " est échappé avec un antislash, le masque [W-\]46] est interprété comme une classe d'un seul caractère, contenant un intervalle de caractères suivi de deux caractères. La valeur octale ou hexadécimale de " ] " peut aussi être utilisée pour déterminer les limites de l'intervalle. Les types de caractères \d , \D , \p, \P, \S , \s , \w , \W peuvent aussi intervenir dans les classes de caractères en y ajoutant les caractères correspondants. Par exemple, " [][\^_`wxyzabc][\dABCDEF] " acceptera n'importe quel caractère hexadécimal. Un accent circonflexe peut aussi être utilisé pour spécifier adroitement des ensembles de caractères plus restrictifs : par exemple [^\W_] accepte toutes les lettres et les chiffres, mais pas les soulignés. Tous les caractères non alpha- numériques autres que \, -, ^ (placés en début de chaîne) et ] n'ont pas de signification particulière, mais ils ne perdront rien à être échappés. Les seuls métacaractères qui ne sont pas reconnus dans les classes de caractères sont l'antislash, le trait d'union (uniquement dans le cas où il peut être compris comme un déterminant d'un intervalle), l'accent circonflexe (uniquement dans le cas où il est placé en début de chaîne), le crochet ouvrant (uniquement là où il peut être compris comme l'entrée du nom de la classe POSIX, - voir le paragraphe suivant) et le crochet fermant. Cependant, l'échappement avec l'antislash de tous les caractères non alphanumériques est toujours utile. Classes de caractères POSIX PCRE supporte la légende de POSIX pour les classes de caractères. Par exemple [01[:alpha:]%] correspond à "0", "1", n'importe quel caractère alphabétique ou à "%". Les noms des classes suivants sont supportés ◆alnum des caractères alphanumériques, ◆alpha des caractères alphabétiques, ◆ascii des codes de caractères 0 – 127, ◆blank un espace ou une tabulation, ◆cntrl des caractère de contrôle, ◆digit des chiffres hexadécimaux (identique à \d), ◆graph des caractère visibles excepté l'espace, ◆lower des minuscules, ◆print des caractères visibles y compis l'espace, ◆punct des caractères visibles excepté les caractères alphanumériques, ◆space un caractère d'espace blanc (n'est pas tout à fait identique à \s), ◆upper majuscules, ◆word des caractères alphanumériques (identique à \w), ◆xdigit chiffres décimaux. Barre verticale (|) La barre verticale | sert à séparer des masques alternatifs. Par exemple, dans le masque " /gilbert|sullivan/ " recherche soit "gilbert", soit "sullivan". Le nombre d'alternatives n'est pas limité, et il est même possible d'utiliser la chaîne vide. Lors de la recherche, toutes les alternatives sont testées, de gauche à droite, et la première qui est acceptée est utilisée. Si les alternatives sont dans un sous-masque (voir ci-dessous), elles ne réussiront que si le masque principal réussit aussi. Installation des options internes Les options PCRE_CASELESS, PCRE_MULTILINE et PCRE_EXTENDED peuvent être modifiéés de manière locale dans le masque avec une séquence de caractères-options Perl se trouvant entre les symboles "(?" et ")". Caractères-options : ◆i pour PCRE_CASELESS ◆m pour PCRE_MULTILINE ◆x pour PCRE_EXTENDED Par exemple (?im) spécifie une recherche multi-lignes insensible à la casse. Il est également possible de désactiver les options avec un échappement par un trait d'union ; vous pouvez aussi combiner l'activation et la désactivation des options, par exemple(?im-x) active les options PCRE_CASELESS et PCRE_MULTILINE mais désactive PCRE_EXTENDED. Si le trait d'union est précédé ou suivi d'un caractère, l'option est désactivée. Sous-masques Les sous-masques sont délimités par des parenthèses, et peuvent être imbriqués. Ajouter des sous-masques a deux utilités : 1.Délimiter des alternatives. Par exemple, le masque cat(aract|erpillar|) correspond à un des mots : "cat", "cataract" ou "caterpillar". Sans les parenthèses, il n'accepterait que "cataract", "erpillar" ou une ligne vide. 2.Le sous-masque est considéré comme capturant : lorsqu'une chaîne sujet est acceptée par le masque complet, les sous-masques sont transmis à l'appelant grâce à un vecteur de sous-masques. Les parenthèses ouvrantes sont comptées de gauche à droite, (commençant à 1) et leur numéros d'ordre servent à numéroter les sous-masques respectifs dans le résultat. Par exemple, si la ligne "the red king" est mise en comparaison avec le masque the ((red|white) (king|queen)) les sous-masques "red king", "red" et "king" seront capturés et numérotés respectivement 1, 2 et 3. L'ubiquité des parenthèses n'est pas toujours simple d'emploi. Parfois, regrouper des sous-masques est nécessaire, sans pour autant capturer la valeur trouvée. Si une parenthèse ouvrante est suivie de " ?: ", le sous-masque ne capture pas la chaîne assortie, et ne sera pas compté lors de la numérotation des captures. Par exemple, avec la chaîne " the white queen ", utilisée avec le masque ((?:red|white) (king|queen)) les chaînes capturées seront "white queen" et "queen", numérotées respectivement 1 et 2 Le nombre maximal de chaînes capturées est de 65535, et le nombre total maximum (niveau d'emboîtement) de sous-masques (capturant ou non) est de 200. Dans le cas où le masque non capturant doit comprendre des options supplémentaires, il est possible d'utiliser l'astuce suivante : placez le caractère correspondant à une option à activer entre "?" et ":". Ainsi, les deux masques suivants (?i:saturday|sunday) (?:(?i)saturday|sunday) vont correspondre à la même chaîne. Puisque les alternatives sont vérifiées de gauche à droite et les options activées sont prises en compte jusqu'à la fin du masque, l'option activée dans une alternative est également activée dans toutes les alternatives suivantes. Ainsi, les masques ci-dessus accepteront aussi bien "SUNDAY" que "Saturday". Répétitions Les répétitions sont spécifiées avec des quantificateurs, qui peuvent être placés à la suite des caractères suivants : ◆caractère alphabétique de données, ◆métacaractère . (point), ◆séquence de contrôle \C, ◆séquence de contrôle correspondant à un caractère, par exemple \d, ◆classe de caractères, ◆référence arrière (voir le paragraphe précédent), ◆sous-masque délimité pas des parenthèses (à moins que ce ne soit une assertion). Les quantificateurs généraux précisent un nombre minimum et maximum de répétitions possibles, donnés par deux nombres entre accolades, et séparés par une virgule. Ces nombres doivent être inférieurs à 65536, et le premier nombre doit être égal ou inférieur au second. Par exemple z{2,4} accepte " zz ", " zzz ", ou " zzzz ". L'accolade fermante n'a pas de signification par elle-même. Si le second nombre est omis, mais que la virgule est là, cela signifie qu'il n'y a pas de limite supérieure. Si le second nombre et la virgule sont omis, le quantificateur correspond au nombre exact de répétitions attendues. Par exemple : [aeiou]{3,} accepte n'importe quelle succession d'au moins 3 voyelles minuscules, tandis que \d{8} n'accepte que 8 chiffres exactement. Une accolade ouvrante qui apparaît à une position où le quantificateur n'est pas accepté, ou si la syntaxe des quantificateurs n'est pas respectée, sera considérée comme littérale. Par exemple, " {,6} " n'est pas un quantificateur, mais une chaîne de 4 caractères. Le quantificateur {0} est autorisé, mais l'expression est alors ignorée. Par convenance (et pour la compatibilité ascendante), les trois quantificateurs les plus communs ont une abréviation d'un seul caractère : ◆* équivalent à {0,} ◆+ équivalent à {1,} ◆? équivalent à {0,1} Il est possible de constituer des boucles infinies en créant un sous-masque sans caractères, mais pourvu d'un quantificateur sans limite supérieure. Par exemple (a?)* Par défaut, les quantificateurs sont dits "gourmands", c'est-à-dire, qu'ils cherchent d'abord à trouver le nombre maximal de répétitions qui autorise le succès de la recherche. L'exemple classique posé par cette gourmandise est la recherche de commentaires d'un programme en C. Les commentaires apparaissent entre les séquences /*....*/ et à l'intérieur de ces délimiteurs, les * et / sont autorisés. Appliquer le masque /\*.*\*/ à la chaîne /* firs comment */ not comment /* second comment */ ne peut réussir, car le masque travaille sur toute la chaîne, à cause de la gourmandise du caractère *. Cependant, un quantificateur suivi d'un point d'interrogation cesse d'être gourmand, et au contraire, ne recherche que le nombre minimum de répétitions. Dans ces conditions, le masque /\*.*?\*/ trouvera bien les commentaires du code C. La signification des autres quantificateurs n'est pas modifiée, ils assurent un nombre approprié de répétitions. Attention à ne pas confondre l'utilisation du point d'interrogation ici avec son utilisation comme quantificateur lui-même. A cause de cette ambiguité, il peut être nécessaire de le doubler : \d??\d Ce masque va tenter de lire un seul chiffre, mais le cas échéant, il acceptera 2 chiffres pour permettre à la recherche d'aboutir. Si l'option PCRE_UNGREEDY est activée, alors les quantificateurs sont non gourmands par défaut, mais peuvent être rendus gourmands au cas par cas, en ajoutant un point d'interrogation après. En d'autres termes, cette option inverse le comportement par défaut. Lorsqu'un sous-masque est quantifié avec un nombre minimum de répétitions, qui soit plus grand que 1, ou avec un maximum de répétitions, le masque compilé aura besoin de plus de place de stockage, proportionnellement au minimum et au maximum. Groupement des éléments et quantificateurs possessifs Si aucune coïncidence n'est obtenue lors d'un nombre maximum de répétitions ainsi qu'en cas d'un nombre minimum de répétitions, ceci entraîne une reprise de comparaison de la chaîne répétitive afin de vérifier si un autre nombre de répétitions permet d'obtenir une coïncidence avec la partie restante du masque. Dans certains cas, il est nécessaire de changer la logique décrite pour réaliser une comparaison spécifique ou afin de minimiser le nombre de tentatives de comparaison (si l'auteur est sûr que continuer les recherches n'a pas de sens). Prenons par exemple le masque \d+foo à appliquer à la chaîne suivante : 123456bar Après avoir capturé les 6 chiffres et sans trouver une coïncidence avec "foo", le moteur de recherche effectue encore une tentative de trouver une coïncidence pour l'élément \d+, mais cette fois, avec 5 chiffres, en cas d'échec, les 4 chiffres seront mis en comparaison etc. Le «groupement des éléments» (dit atomic grouping ou groupement atomique, selon le terme utilisé par Jeffrey Friedl dans son livre) indique que dans le cas où une partie de masque coïncide, elle ne doit pas être analysée de nouveau. Si nous utilisons le groupement dans l'exemple donné ci-dessus, le moteur de recherche arrête la recherche dès qu'il détecte une coïncidence avec "foo" pour la première fois. Les simples masques s'écrivent avec les parenthèses de la manière suivante : (?>. Par exemple : (?>\d+)foo Utilisés de cette façon, les parenthèses "verrouillent" la partie du masque qu'elles délimitent lors de la première détection d'une coïncidence; en cas de détection de non coïncidence avec la partie restante du masque, les parenthèses empêchent la reprise de l'analyse de la partie verrouillée. Cependant, ceci n'empêche pas de reprendre l'analyse d'autres éléments y compris ceux qui précèdent le groupe. Autrement dit, le sous-masque de ce type correspond à la ligne de caractères avec laquelle on pourrait mettre en comparaison un autre masque identique s'il était ancré à la position courante de la chaîne. Les sous-masques de groupement atomique ne sont pas capturants. Les exemples équivalents à celui ci-dessus peuvent être classés comme une capture inconditionnelle d'un nombre maximum de coïncidences. Ainsi, tandis que \d+ et \d+? sont utilisés pour ajuster le nombre de chiffres à correspondre afin que la partie restante du masque puisse coïncider, (?>\d+) peut correspondre seulement à toute séquence des chiffres. Les groupes atomiques peuvent comprendre n'importe quels sous-masques complexes, ils peuvent aussi être imbriqués. Cependant, lorsque un sous-masque utilisé pour le groupement est un élément simple qui se répéte, tout comme dans l'exemle ci-dessus, il est possible d'utiliser un déterminant plus simple dit «quantificateur possesif». Le quantificateur possesif est spécifié avec un signe additionnel plus + placé après le quantificateur. Dans ce cas, l'exemple donné ci-dessus peut être interprété de la manière suivante \d++foo Les quantificateurs possessifs sont toujours gourmands ; l'activation de l'option PCRE_UNGREEDY est ignorée. Les quantificateurs représentent un moyen très commode pour désigner les simples formes du groupement atomique. Cependant, il n'y a pas de différence dans les valeurs ni dans le traitement d'un quantificateur possesif ou d'un groupe atomique. Si le masque contient une répétition illimitée à l'intérieur du sous-masque, compte tenu du fait que ce dernier peut également être répété un nombre illimité de fois, l'utilisation du groupement atomique est le seul moyen permettant d'éviter des fausses coïncidences pouvant prendre beaucoup de temps. Le masque (\D+|<\d+>)*[!?] correspond à un nombre illimité de sous-lignes qui ne contiennent pas de chiffres ou contiennent des chiffres délimités par les symboles <> suivis d'un point d'exclamation ! ou d'un point d'interrogation ?. Le processus est assez rapide en cas de détection d'une coïncidence. Cependant, l'exemple suivant prendra beaucoup de temps aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa avant que la conclusion de non correspondance ne soit établie. Ceci est possible puisque la ligne peut être délimitée de diverses manières entre une répétition interne \D+ et une répétition externe *, mais toutes les répétitions doivent être vérifiées. (L'exemple utilise [!?], ce qui est préférable par rapport à un caractère simple à la fin, puisque PCRE prévoit une optimisation qui permet la détection rapide des non coïncidences lors de l'utilisation d'un caractère simple. Le dernier caractère simple nécessaire à la correspondance sera mémorisé, dans le cas où le caractère n'est pas présent dans la chaîne, le résultat de non coïncidence revient très vite). Lorsque le masque est modifié en utilisant le groupement atomique, comme par exemple dans le cas suivant : ((?>\D+)|<\d+>)*[!?] la séquence de caractères non numériques ne peut être rompue et la conclusion de non coïncidence se fait rapidement. Les références arrières En dehors des classes de caractères, un antislash suivi d'un nombre plus grand que 0 (et plusieurs chiffres suivants) est une référence arrière (c'est-à-dire vers la gauche) dans le masque, en supposant qu'il y ait suffisamment de sous-masques capturants précédents (parenthèses ouvrantes). Cependant, si le nombre décimal suivant l'antislash est plus petit que 10, il sera toujours considéré comme une référence arrière, et cela générera une erreur si le nombre de captures n'est pas suffisant. En d'autres termes, il faut qu'il existe suffisamment de parenthèses ouvrantes à gauche de la référence, surtout si la référence est inférieure à 10. Reportez-vous à la section "Caractères invisibles" pour avoir de plus amples détails à propos du traitement des chiffres qui suivent l'antislash. La référence arrière remplace ce qui a été capturé par un sous-masque dans le masque courant, plutôt que de remplacer le sous-masque lui-même. Ainsi le masque
(sens|respons)e and \1ibility trouvera "sense and sensibility" et "response and responsibility", mais pas "sense and responsibility". Si la recherche tient compte de la casse, alors la casse de la chaîne capturée sera importante. Par exemple, ((?i)rah)\s+\1 trouve "rah rah" et "RAH RAH", mais pas "RAH rah", même si le sous-masque capturant initial ne tenait pas compte de la casse Les références arrières relatives aux sous-masques décrits utilisent la syntaxe Python (?P=name). L'exemple cité ci-dessus pourrait être interprété de la manière suivante : (?(?i)rah)\s+(?P=p1) Il peut y avoir plusieurs références arrières dans le même sous-masque. Si un sous-masque n'a pas été utilisé dans une recherche, alors les références arrières échoueront. Par exemple le masque (a|(bc))\2 échouera toujours s'il trouve une correspondance avec "a" plus tôt qu'avec "bc". Puisque le sous-masque peut contenir plusieurs parenthèses capturantes, tous les chiffres suivant l'antislash sont compris comme une partie de la référence arrière potentielle. Si le masque recherche un chiffre après la référence, alors il faut impérativement utiliser des délimiteurs pour terminer la référence arrière. Si l'optionPCRE_EXTENDED est activée, on peut utiliser un espace. Sinon, un commentaire vide fait l'affaire. Une référence arrière qui intervient à l'intérieur de parenthèses auxquelles elle fait référence échouera dès que le sous-masque sera utilisé. Par exemple, (a\1) échouera toujours. Cependant, ces références peuvent être utiles dans les sous-masques répétitifs. Par exemple le masque. (a|b\1)+ pourra convenir pour "a" et "aba", "ababbaa", etc. À chaque itération du sous-masque, la référence arrière utilise le résultat du dernier sous-masque. Pour que cela fonctionne, il faut que la première itération n'ait pas besoin d'utiliser la référence arrière. Cela arrive avec les alternatives, comme dans l'exemple ci-dessus, ou avec un quantificateur de minimum 0. Assertions Une assertion est un test sur les caractères suivant ou précédant celui qui est en cours d'étude et ne concerne pas les caractères depuis la chaîne sujet. Les assertions simples \b, \B, \A, \G, \Z, \z, ^ et $ sont décrites précédemment. Il existe cependant des types d'assertions plus complexes, codées sous la forme de sous-masques. Il en existe deux types : celles qui travaillent au-delà de la position courante, et celles qui travaillent en-deça. Une assertion se comporte comme un sous-masque, hormis le fait qu'elle ne déplace pas le pointeur de position. Les assertions ne sont pas capturantes, et ne peuvent pas être répétées. Si une assertion contient des sous-masques capturants en son sein, ils seront compris dans le nombre de sous-masques capturants du masque entier. La capture est réalisée pour les assertions positives, mais cela n'a pas de sens pour les assertions négatives. Assertions avant Les assertions avant commencent par (?= pour les assertions positives, et par (?! , pour les assertions négatives. Par exemple
\w+(?=;) s'assure qu'un mot est suivi d'un point-virgule, mais n'inclut pas le point virgule dans la capture. D'autre part, foo(?!bar) correspond à tout "foo" trouvé non suivi de "bar". Il est à noter que le masque (?!foo)bar en est proche, mais ne trouve pas une occurrence de " bar " qui soit précédée par quelque chose d'autre que " foo foo"; il trouve toutes les occurrences de " bar ", quel que soit ce qui le précède, car l'assertion (?!foo) est toujours vraie quand les trois caractères suivants sont " bar". Une assertion arrière est ici nécessaire. Pour arrêter la recherche dans un point spécifié du masque, il vaut mieux utiliser (?!), puisque la ligne vide est toujours mise en comparaison et ainsi l'assertion exigeant qu'il n'y ait pas de ligne vide échouera toujours. Assertions arrières Les assertions arrières commencent par (?<= pour les assertions positives, et (?<! pour les assertions négatives. Par exemple, (?<!foo)bar trouve les occurrences de "bar" qui ne sont pas précédées par "foo". Le contenu d'une référence arrière est limité de telle façon que les chaînes qu'il utilise soient toujours de la même taille. Cependant, lorsqu'il y a plusieurs alternatives, elles n'ont pas besoin d'être de la même taille, (?<=bullock|donkey) est autorisé, tandis que (?<!dogs?|cats?) provoque une erreur. Les alternatives qui ont des longueurs différentes ne sont autorisées qu'au niveau supérieur des assertions arrières. Une assertion telle que (?<=ab(c|de)) n'est pas autorisée, car l'assertion de bas niveau (la deuxième, ici) a deux alternatives de longueurs différentes. Pour la rendre acceptable, il faut écrire: (?<=abc|abde) L'implémentation des assertions arrières déplace temporairement le pointeur de position vers l'arrière, et cherche à vérifier l'assertion. Si le nombre de caractères est différent, la position ne sera pas correcte, et l'assertion échouera. PCRE n'autorise pas la séquence d'échappement \C dans les assertions arrières puisqu'il est impossible de calculer la longueur de vérification arrière. La séquence d'échappement \X pouvant correspondre à des nombres divers d'octets n'est pas autorisée non plus. La combinaison d'assertions arrières avec des groupes atomiques peut être particulièrement pratique à la fin des chaînes afin de désigner les correspondances efficaces. Envisageons l'application du masque simple suivant : abcd$ à une longue chaîne non correspondante au masque. Puisque la recheche se fait de gauche à droite, PCRE vérifie d'abord chaque "a" dans le sujet et commence à analyser seulement après les éléments suivants dans le masque. Si le masque est spécifié de la manière suivante, ^.*abcd$ D'abord, .* est comparé à toute la ligne et lorsque la recherche échoue (puisqu'il n'y a aucun "a"),la comparaison avec tous les caractères sauf le dernier sera effectuée , puis la procédure sera reprise, exceptés les deux derniers caractères etc. Finalement, la recherche de "a" prend toute la ligne de droite à gauche ce qui n'est pas mieux par rapport à la recherche précédente. Mais si le masque est spécifié de la manière ci-dessous ^(?>.*)(?<=abcd) ou avec la syntaxe de quantificateur possessif (ce qui est identique) ^.*+(?<=abcd) la reprise de recherche pour le symbole .* ne se fait pas; il ne peut que correspondre à la ligne entière. L'assertion arrière suivante ne vérifie qu'une seule fois les quatres derniers caractères. Si la recherche échoue, toute la correspondance échoue immédiatement. Lors de l'analyse des longues lignes, la différence de durée peut être importante. Utilisations de plusieurs assertions Plusieurs assertions peuvent intervenir successivement, leur nombre n'est pas limité. Par exemple, le masque (?<=\d{3})(?<!999)foo recherche les chaînes "foo", précédées par trois chiffres qui ne sont pas "999". Notez que chaque assertion est appliquée indépendamment, au même point de la chaîne à traiter. Tout d'abord, il est vérifié que les trois premiers caractères ont tous des chiffres, puis on s'assure que ces trois caractères ne sont pas "999". Le masque précédent n'accepte pas "foo", précédé de 6 caractères, les trois premiers étant des chiffres et les trois suivants étant différents de "999". Par exemple, ce masque n'acceptera pas la chaîne "123abc-foo". Pour ce faire, il faut utiliser le masque suivant : (?<=\d{3}...)(?<!999)foo Dans ce masque, la première assertion vérifie les six premiers caractères, s'assure que les trois premiers sont des entiers, et la deuxième assertion s'assure que les trois derniers caractères ne sont pas "999". De plus, les assertions peuvent être imbriquées. Par exemple (?<=(?<!foo)bar)baz recherche les occurrences de "baz" qui sont précédées par "bar" qui, à son tour, n'est pas précédé par "foo", tandis que (?<=\d{3}(?!999)...)foo est un autre masque, qui recherche les caractères "foo", précédés par trois chiffres, suivis de trois autres caractères qui ne forment pas "999". Sous-masques conditionnels Il est possible de lier un sous-masque à une condition, ou de choisir entre deux sous-masques alternatifs, en fonction du résultat d'une assertion, ou suivant les résultats de recherche précédents. Les deux formes possibles de sous-masques conditionnels sont (?(condition)yes-pattern) (?(condition)yes-pattern|no-pattern) Si les conditions sont satisfaites, le masque positif est utilisé, sinon, le masque négatif est utilisé, s'il existe. S'il y a plus de deux alternatives, une erreur est générée à la compilation. Il y a trois types de conditions : si le texte entre parenthèses est une séquence de chiffres, alors la condition est satisfaite si le sous-masque correspondant à ce numéro a réussi. Le nombre doit être positif. Considérons le masque suivant, qui contient des espaces non significatifs pour le rendre plus compréhensible (on supposera l'option PCRE_EXTENDED activée) et qui est divisé en trois parties pour simplifier les explications : ( \( )? [^()]+ (?(1) \) ) La première partie recherche une parenthèse ouvrante optionnelle et, si elle existe, elle est capturée. La deuxième partie recherche une séquence de caractères qui ne contiennent pas de parenthèses. La troisième partie est conditionnée à la première, et s'assure que s'il y a une parenthèse ouvrante, il en existe une fermante. Si une parenthèse ouvrante a été trouvée, elle a été capturée, et donc la première capture existe, et la condition est exécutée. Sinon, elle est ignorée. Ce masque recherche donc une séquence de lettres, éventuellement placées entre parenthèses. Si la condition est la chaîne (R), elle sera satisfaite si un appel récursif au masque ou au sous-masque a été fait. Au premier appel, la condition n'est pas vérifiée. Si la condition n'est pas une séquence de chiffres, il faut que ce soit une assertion. Ce peut être une assertion positive ou négative, arrière ou avant. Considérons le masque suivant (mêmes conditions que le précédent) et avec deux alternatives en seconde ligne : (?(?=[^a-z]*[a-z]) \d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) La condition est une assertion avant positive, qui recherche une séquence optionnelle de caractères non-lettres. En d'autres termes, elle teste la présence d'au moins une lettre dans la chaîne sujet. Si une lettre est trouvée, la recherche se poursuit avec la première alternative, et sinon, avec la seconde. Ce masque recherche des chaînes de la forme : dd-aaa-dd ou dd-dd-dd, avec aaa qui sont des lettres et dd qui sont des chiffres.
|