La section précédente couvrait la syntaxe des expressions régulières. Elle utilisait l'interface la plus simple avec le comparateur : envoyer le message #matchesRegex: à la chaîne à analyser avec l'expression régulière en argument. Cette section présente des usages plus complexes du comparateur.
Une chaîne (classe String) comprend aussi ces messages :
#prefixMatchesRegex: regexString | |
#matchesRegexIgnoringCase: regexString |
|
#prefixMatchesRegexIgnoringCase: regexString |
Les 2 derniers messages sont des versions insensibles à la casse des comparateurs.
#prefixMatchesRegex: est identique à #matchesRegex, excepté que le récepteur n'a pas à correspondre entièrement à l'expression régulière passée en argument. Correspondre au début du récepteur suffit. Par exemple :
'abcde' matchesRegex: '(a|b)+' | -- false | |
'abcde' prefixMatchesRegex: '(a|b)+' |
-- true |
Il peut être intéressant pour une application de connaître toutes les correspondances d'une expression régulière avec une chaîne. On accède aux correspondances en utilisant un protocole d'énumération utilisé par les classes de type Collection :
#regex: regexString matchesDo: unBloc |
Évalue un bloc à un argument unBloc pour chaque correspondance de l'expression régulière avec la chaîne réceptrice.
#regex: regexString matchesCollect: unBloc |
Évalue un bloc à un argument unBloc pour chaque correspondance de l'expression régulière avec la chaîne réceptrice. Collecte les résultats de l'évaluation et les renvoie comme une SequenceableCollection.
#allRegexMatches: regexString |
Renvoie une collection de toutes les correspondances (sous-chaînes de la chaîne réceptrice) de l'es l'expression régulière. Équivalentà aString regex: regexString matchesCollect: [each | each].
Il est possible de remplacer toutes les correspondances d'une expression régulière avec une certaines chaîne en utilisant le message :
#copyWithRegex: regexString matchesReplacedWith: aString |
Par exemple :
'ab cd ab' copyWithregex: '(a|b)+' matchesReplacesWith: 'foo' |
Un mode de substitution plus général est la traduction des correspondances :
#copyWithRegex: regexString matchesTranslatedUsing: unBloc |
Ce message évalue un bloc en lui passant chaque correspondance de l'expression régulière avec le récepteur et en retournant une copie du récepteur modifié. Chaque correspondance en fonction des résultats du bloc. Par exemple :
'ab cd ab' copyWithregex: '(a|b)+' matchesTranslatedUsing: [:each| each asUppercase] |
Tous les messages des protocoles d'énumération et de remplacement sont sensibles à la casse. Les versions non sensibles ne font pas parties du protocole CharacterArray. Elles sont disponibles par une interface de bas niveau.
Le fonctionnement de #matchesRegex est le suivant :
Si vous comparez de façon répétitive un certain nombre de chaînes à la même expression régulière en utilisant les messages de la classe String que nous venons de voir, l'expression régulière est analysée et un comparateur est créé pour chaque nouvelle comparaison. Vous pouvez éviter ce gaspillage en construisant un comparateur pour l'expression régulière et en le réutilisant autant que nécessaire. Vous pouvez par exemple créer un comparateur au moment de l'initialisation d'une classe ou d'une instance, et le stocker dans une variable pour un usage ultérieur.
Vous pouvez créer un comparateur en utilisant une de ces méthodes :
Une manière plus pratique consiste à utiliser un des 2 messages de création de comparateur compris par les chaînes.
Voici 4 exemples de création de comparateurs :
hexRecognizer := RxMatcher forString: '16r[0-9A-Fa-f]+' | |
hexRecognizer := RxMatcher forString: '16r[0-9A-Fa-f]+' ignoreCase: false | |
hexRecognizer := '16r[0-9A-Fa-f]+' asRegex | |
hexRecognizer := '16r[0-9A-F]+' asRegexIngnoringCase |
Le comparateur comprend ces messages (tous retournent true pour indiquer une comparaison ou une recherche fructueuse, et false autrement) :
matches: aString |
Vrai si la chaîne cible correspond entièrement |
matchesPrefix: aString |
Vrai si le début de la chaîne cible correspond (pas nécessairement toute la chaîne) |
search: aString |
Cherche la première occurence d'une sous-chaîne. (Notez que les 2 premières méthodes essaient de trouver une correspondanceà partir du tout début de la chaîne). Si l'on utilise l'exemple ci-dessus avec un comparateur pour 'a+', cette méthode retourne true si on lui passe l'argument 'baaa', alors que les 2 autres méthodes retournent false. |
matchesStream: aStream | |
matchesStreamPrefix: aStream | |
searchStream: aStream |
Respectivement analogues aux 3 méthodes précédentes, elle prennent un Stream et non une chaîne en argument. Ce Stream doit être positionnable et lisible. |
Toutes ces méthodes retournent un booléen. Le comparateur stocke la dernière valeur retournée et peut la restituer :
lastResult |
Retourne un booléen -- le résultat de la dernière comparaison. Si aucune comparaison n'a été effectuée, le résultat est indéterminé. |
Après une comparaison fructueuse, vous pouvez demander quelle partie de la chaîne originale a été reconnue par quelle partie de l'expression régulière.
Une sous-expression est une partie de l'expression régulière mise entre parenthèses, ou l'expression en entier. Quand une expression régulière est compilée, ses sous-expressions se voient assigner un indice commençant à 1, de gauche à droite. Par exemple, '((ab)+(c|d))?ef' comprend les sous-expressions suivantes avec leurs indices :
1 | ((ab)+(c|d))?ef | l'indice 1 représente l'expression complète | ||
2 |
(ab)+(c|d) |
|||
3 | ab | |||
4 | c|d |
Après une comparaison fructueuse, le comparateur peut indiquer quelle partie de la chaîne originale correspond à quelle sous-expression. Il comprend ces messages :
subexpressionCount |
Renvoie le nombre total de sous-expressions : la plus haute valeur qui peut être utilisée comme index avec ce comparateur. Cette valeur est disponible immédiatement après l'initialisation et est constante. |
subexpressionCount: unIndex |
unIndex doit être valide (valeur inférieure ou égale à subexpressionCount) et ce message ne peut être envoyé qu'après une comparaison réussie. Cette méthode retourne une sous-chaîne correspondant à la sous-expression. |
subBeginning: unIndex | |
subEnd: unIndex |
Retourne les positions dans la chaîne originale ou le Stream, où la correspondance de la sous-expression pointée par l'index a respectivement commencé, et terminé. |
L'utilitaire qui suit permet d'extraire des éléments d'une de structure complexe. Par exemple le code suivant utilise l'expression au format 'MMM JJ, 19YY' que nous avons déjà vu à la section Syntaxe, pour convertir une date en un tableau de 3 éléments :
|matcher|
matcher := Rxmatcher forString: '(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[ ]+(:isDigit::isDigit:?)[ ]*,[ ]*19(:isDigit::isDigit:)'.
(matcher matches: 'Aug 6, 1996')
ifTrue:
[Array
with: (matcher subexpression: 4)
with: (matcher subexpression: 2)
with: (matcher subexpression: 3)]
ifTrue: ['no match']
(devrait retourner '#('96' 'Aug' '6')').
Les protocoles d'énumération et de remplacement utilisés avec les tableaux de caractères sont en fait implémentés par le comparateur. Les messages suivants sont définis :
#matchesIn: uneChaine | |
#matchesIn: uneChaine do: unBloc | |
#matchesIn: uneChaine collect: unBloc | |
#copy: uneChaine replacingMatchesWith: chaineDeRemplacement | |
#copy: uneChaine translatingMatchesUsing: unBloc | |
#matchesOnStream: unStream | |
#matchesOnStream: unStream do: unBloc | |
#matchesOnStream: unStream collect: unBloc | |
#copy: streamSource to: streamCible replacingMatchesWith: chaineDeRemplacement | |
#copy: streamSource to: streamCible translatingMatchesWith: unBloc |
Si une erreur de syntaxe est détectée pendant l'analyse de l'expression, erreur RxSyntaxError est levée.
Si une erreur est détectée pendant la construction d'un comparateur, une erreur RxCompilationError est levée.
Si une erreur est détectée pendant une comparaison (par exemple si une sélecteur incorrect a été spécifié en utilisant la syntaxe :<sélecteur>:, ou à cause d'une erreur interne au comparateur, une erreur RxMatcherError est levée.
Ces trois erreurs ont RxError pour parent. Puisque ces 3 signaux peuvent être levés lors d'un appel à #matchesRegex, RxError est commode pour les capturer tous les 3. Par exemple :
'abc' matchesRegex: '))garbage['
on: RxError
do: [:ex | ex return: false]Dernière modification le 10-03-2002