12
votes

Masquage de la longueur variable avec Preg_Replace

Je masque tous les caractères entre guillemets simples (inclusivement) dans une chaîne en utilisant Preg_replace_callback () code>. Mais j'aimerais seulement utiliser Preg_replace () code> si possible, mais je n'ai pas été capable de le comprendre. Toute aide serait appréciée.

C'est ce que j'ai à l'aide de Preg_replace_callback () code> qui produit la sortie correcte: p>

TEST -- ok -


6 commentaires

Vous ne pouvez pas obtenir le SHLEN du match sans le rappel. Vous auriez besoin de faire correspondre chaque personnage individuellement. Inutile de dire que le rappel est beaucoup mieux ici. Pourquoi ne voulez-vous pas utiliser un rappel?


J'essaie juste de simplifier si possible. Merci


J'ai l'impression que ceci est possible avec regex et la solution acceptée est fausse ... mais je vais devoir retourner quand j'ai plus de temps.


Si cela simplifie les choses, j'ai réalisé que le remplacement des citations simples est facultatif pour mon problème particulier. Une solution qui remplace les caractères entre toutes les paires de citations simples, à l'exclusion des devis simples fonctionnerait également. Il était tout simplement plus facile de remplacer les guillemets simples lors de l'utilisation de Preg_replace_Callback ().


En regardant 2 solutions Regex ci-dessous, j'espère vraiment que vous gardez votre solution de rappel. C'est beaucoup plus lisible.


La solution de rappel est également plus rapide dans une boucle.


3 Réponses :


16
votes

Oui, vous pouvez le faire, (en supposant que les citations sont équilibrées) Exemple: xxx

L'idée est la suivante: vous pouvez remplacer un caractère s'il s'agit d'une citation ou s'il est suivi d'un nombre impair de guillemets.

sans guillemets: xxx

Le motif correspondra à un caractère uniquement lorsqu'il est contigu à une correspondance précédente (en d'autres termes, quand il est immédiatement après le dernier match) ou lorsqu'il est précédé d'une citation qui n'est pas contiguë à la correspondance précédente.

\ g est la position après la dernière correspondance (au début, il est Le début de la chaîne)

Détails du motif: xxx

Notez que, étant donné que la citation de fermeture n'est pas assortie par le motif, les caractères suivants qui ne sont pas Les citations ne peuvent pas être assorties car il n'y a pas de match précédent.

EDIT:

Le (* Skip) (* échouez) WAY:

au lieu de tester si une citation unique n'est pas Une citation de fermeture avec (?: (?! \ g) | \ a) ' Comme dans le motif de précédent, vous pouvez casser la contiguïté de correspondance sur les guillemets en utilisant les verbes de contrôle de la rampe (* Skip) et (* échoue) (qui peut être raccourci vers (* f) ). xxx

puisque le motif échoue sur chaque citation de fermeture, les caractères suivants ne seront pas assortis avant la prochaine citation d'ouverture.

Le motif peut être plus efficace. Écrit comme ceci: xxx

(vous pouvez également utiliser (* pruneau) à la place de (* Skip) .)


3 commentaires

Merci. Cela résout le problème. J'ai réalisé plus tard que le remplacement des citations simples n'est pas vraiment nécessaire, mais était plus facile à le faire avec Preg_replace_callback (). Votre solution pourrait-elle être simplifiée si je n'avais pas besoin de remplacer les citations simples environnantes? Merci


@Alan: J'ai ajouté une version sans guillemets, le motif est vraiment plus court et plus efficace que le premier. (Moins de tests)


Merci pour l'entrée de tous! Aller avec cette solution (regex la plus courte).



12
votes

Réponse courte: c'est possible !!!

Utilisez le modèle suivant P>

~                   # A modifier
#################################### Rule 1 ####################################
'                   # A single quote
(?=                 # Lookahead to make sure there is an odd number of single quotes ahead
   (?:              # non-capturing group
      (?:           # non-capturing group
         [^'\r\n]*  # Match anything that's not a single quote or newline, zero or more times
         '          # Match a single quote
      ){2}          # Repeat 2 times (We'll be matching 2 single quotes)
   )*               # Repeat all this zero or more times. So we match 0, 2, 4, 6 ... single quotes
   (?:
      [^'\r\n]*     # Match anything that's not a single quote or newline, zero or more times
      '             # Match a single quote
      [^'\r\n]*     # Match anything that's not a single quote or newline, zero or more times
      (?:\r?\n|$)   # End of line
   )
)

|                   # Or

#################################### Rule 2 ####################################
\G(?<!^)            # Preceding contiguous match (not beginning of line)
[^']                # Match anything that's not a single quote
(?=                 # Lookahead to make sure there is an odd number of single quotes ahead
   (?:              # non-capturing group
      (?:           # non-capturing group
         [^'\r\n]*  # Match anything that's not a single quote or newline, zero or more times
         '          # Match a single quote
      ){2}          # Repeat 2 times (We'll be matching 2 single quotes)
   )*               # Repeat all this zero or more times. So we match 0, 2, 4, 6 ... single quotes
   (?:
      [^'\r\n]*     # Match anything that's not a single quote or newline, zero or more times
      '             # Match a single quote
      [^'\r\n]*     # Match anything that's not a single quote or newline, zero or more times
      (?:\r?\n|$)   # End of line
   )
)

|                   # Or

#################################### Rule 3 ####################################
\G(?<!^)            # Preceding contiguous match (not beginning of line)
'                   # Match a single quote
~x


2 commentaires

Wow, fou. Dans mon problème particulier, je n'aurais pas un nombre impair de guillemets simples, il est donc un peu plus complexe qu'il n'a besoin que pour mon problème, mais puis-je apprécier la solution approfondie. Et peut-être que cela aidera les autres qui peuvent avoir un problème similaire avec un nombre impair de guillemets simples. Merci!


@ALAN Eh bien, j'ai dit "étrange" depuis le premier que nous faisons correspondre le faire "Même". Un peu déroutant ouais ...



6
votes

Eh bien, juste pour le plaisir de cela et je ne recommanderais sérieusement à quelque chose comme ça parce que j'essaie d'éviter les regards de surveillance quand ils ne sont pas nécessaires, voici une regex qui utilise le concept de ' retour au futur < / em> ': xxx

Démo Regex101 < P> D'accord, il est décomposé en deux parties:

1. Correspondant au début de la citation unique xxx

Les règles que je crois devraient être établies ici sont les suivantes:

  1. Il devrait y avoir ^ ou \ s avant le devis de début (par conséquent (? <= ^ | code>). < / li>
  2. Il n'y a pas de \ s après le devis de début (par conséquent (?! \ s) ).

    2. Faire correspondre les choses à l'intérieur de la citation et la citation finale xxx

    Les règles que je crois devraient être établies ici sont les suivantes:

    1. Le caractère peut être tout caractère (donc . )
    2. Le match est de 1 caractère long et suivant le match précédent immédiat (par conséquent (?! ^) \ g ).
    3. Il ne devrait y avoir aucune citation unique, qui est elle-même suivie d'un espace, avant de (par conséquent

      (? et c'est le' < em> retour au futur 'partie). Cela ne correspond pas efficacement à un \ s précédé d'un ' et marquera la fin des caractères enveloppés entre des guillemets simples. En d'autres termes, la citation de clôture sera identifiée comme un citation unique suivi de \ s .

      Si vous préférez des images ...

       img


6 commentaires

Où est le delorean?


@Casimirthippolyte euh, je ne reçois pas la référence: s


Après, une recherche, c'est un delorean (pas un delorean).


@Casimirthippolyte C'est dans la lunette d'oeil. Cette technique a été appelée «Retour au futur» par Un article mentionné par ZX81 .


Agréable! J'ai essayé une approche similaire mais je ne pouvais pas le faire fonctionner bien. Je me suis arrêté à (?! \ g) '| (?! ^) \ g (?: [^'] | '!!!) - Il correspond à tout sauf la dernière citation. Mon problème était que j'avais besoin de faire correspondre la dernière citation, puis de réinitialiser \ g pour la prochaine correspondance afin qu'il soit arrêté. Vous avez résolu ce problème d'une autre manière: vous avez décidé que les espaces ont un sens au problème, que l'OP n'a jamais indiqué. Par exemple: 'Cela'not-this'this' est en train de remplacer correctement par les autres réponses ( -------------- ), mais pas par le tien. J'ai essayé de jouer avec des verbes ou \ k , mais je ne sais probablement pas assez de tours.


@Kobi En effet, il devait y avoir un moyen de décider de ce qui était une citation étroite et de ce qui n'était pas et c'était la seule façon dont je pouvais penser. L'utilisation de BackRefs ne fonctionnerait pas non plus que des captures ne sont pas «reportées» à partir du match précédent (les backresfs seraient une option s'il s'agissait d'une correspondance continue). En outre, en supposant que doit être remplacé, le regex ci-dessus le ferait correctement. Donc, c'est une sorte de zone grise imo qui nécessite définitivement plus de spécifications.