2016-05-24 1 views
9

D'après ce que je peux recueillir de la documentation Pharo sur regex, je peux définir un objet d'expression régulière comme:chaîne de capture en regex remplacement

re := '(foo|re)bar' asRegex 

Et je peux remplacer l'expression régulière en correspondance avec une chaîne par ceci:

re copy: 'foobar blah rebar' replacingMatchesWith: 'meh' 

Ce qui résultera en: `'meh blah meh'.

Jusqu'ici, tout va bien. Mais je veux remplacer le 'bar' et laisser le préfixe seul. Par conséquent, il me faut une variable pour gérer la capture parenthétique:

re copy: 'foobar blah rebar' replacingMatchesWith: '%1meh' 

Et je veux le résultat: 'foomeh blah remeh'. Cependant, cela me donne juste: '%1meh blah %1meh'. J'ai également essayé d'utiliser \1, ou \\1, ou $1, ou {1} et j'ai obtenu le remplacement littéral de chaîne, par exemple. Comme résultat:, '\1meh blah \1meh'.

je peux le faire assez facilement dans GNU Smalltalk avec:

'foobar blah rebar' replacingAllRegex: '(foo|re)bar' with: '%1meh' 

Mais je ne trouve nulle part dans la documentation regex Pharo qui me dit comment je peux le faire en Pharo. J'ai aussi fait des recherches sur Pharo regex, mais je n'ai rien trouvé. Cette fonctionnalité fait-elle partie de la classe RxMatcher ou d'une autre classe de regex Pharo?

+0

il semble Pharo ne prend pas en charge le remplacement des groupes de capture – rock321987

+0

Eh bien, avez-vous essayé les styles habituels de références arrières? Comme '\ 1', ou' \\ 1' ou '$ 1' (peut-être avec' matchesReplacedWith')? Les groupes de capture sont pris en charge, il est clair à partir de ce que l'appariement peut faire dans Pharo, mais il n'y a aucune indication sur si les références arrières sont prises en charge en tant que parties des modèles de remplacement. –

+1

@ WiktorStribiżew Oui, j'ai essayé '\ 1',' \\ 1', et '$ 1' aussi. Dans chaque cas, le remplacement était la chaîne littérale. J'ai mis à jour ma question en indiquant ces tentatives. Je vois que les groupes de capture sont supportés pour ce qui est de l'appariement. La documentation contient des exemples de capture et d'énumération des captures. Cependant, rien à propos de les référencer dans une chaîne de remplacement. Cela semble fondamental à regex trouver/remplacer à moi, donc je suis surpris que ce n'est pas pris en charge. – lurker

Répondre

1

Après avoir expérimenté un peu avec la classe RxMatcher, je fis la modification suivante au sélecteur RxMatcher#copyStream:to:replacingMatchesWith::

copyStream: aStream to: writeStream replacingMatchesWith: aString 
    "Copy the contents of <aStream> on the <writeStream>, 
    except for the matches. Replace each match with <aString>." 

    | searchStart matchStart matchEnd | 
    stream := aStream. 
    markerPositions := nil. 
    [searchStart := aStream position. 
    self proceedSearchingStream: aStream] whileTrue: [ | ws rep | 
     matchStart := (self subBeginning: 1) first. 
     matchEnd := (self subEnd: 1) first. 
     aStream position: searchStart. 
     searchStart to: matchStart - 1 do: 
      [:ignoredPos | writeStream nextPut: aStream next]. 

     "------- The following lines replaced: writeStream nextPutAll: aString ------" 
     "Do the regex replacement including lookback substitutions" 
     writeStream nextPutAll: (aString format: self subexpressionStrings). 
     "-------" 

     aStream position: matchEnd. 
     "Be extra careful about successful matches which consume no input. 
     After those, make sure to advance or finish if already at end." 
     matchEnd = searchStart ifTrue: 
      [aStream atEnd 
       ifTrue: [^self "rest after end of whileTrue: block is a no-op if atEnd"] 
       ifFalse: [writeStream nextPut: aStream next]]]. 
    aStream position: searchStart. 
    [aStream atEnd] whileFalse: [writeStream nextPut: aStream next] 

Et puis la catégorie "accès":

subexpressionStrings 
    "Create an array of lookback strings" 
    | ws | 
    ws := Array new writeStream. 
    2 to: (self subexpressionCount) do: [ :n | | se | 
     ws nextPut: ((se := self subexpression: n) ifNil: [ '' ] ifNotNil: [ se ]) ]. 
    ^ws contents. 

Avec cette modification, je peux faire un retour dans la chaîne de remplacement en utilisant le modèle Smalltalk String#format: pour les arguments:

re := '((foo|re)ba(r|m))' asRegex 
re copy: 'foobar meh rebam' replacingMatchesWith: '{2}bu{3} (was {1})' 

Résultats dans:

'foobur (was foobar) meh rebum (was rebam)' 
0

Avez-vous vérifié l'aide de Regex? Il n'y a pas #replacingAllRegex:, mais le matcher a #subexpression:

+0

N'est-ce pas vraiment un commentaire? ;) J'ai lu toute la documentation en ligne sur Pharo regex je pourrais trouver (qui sont à peu près tous les mêmes instances réitérées). Je sais qu'il n'y a pas de #replacingAllRegex: dans Pharo.Je citais cela comme un exemple de ce que je pouvais faire dans GNU Smalltalk. Je sais que le matcher a '#subexpression:' mais il n'y a pas de sélecteur pour effectuer un remplacement de regex qui a des références à ces sous-expressions et telles qu'elles existent dans les bibliothèques regex d'autres langages (y compris GNU Smalltalk). Si je me trompe, pouvez-vous me montrer un exemple? – lurker