3 votes

comment exclure un caractère dans une classe de caractères d'un modèle regex si le dernier caractère ?

Désolé si la question est mal formulée (ou si elle a déjà été posée. J'ai vraiment essayé de la trouver).

Est-il possible, si un personnage spécifique d'une classe de personnages se trouve être le dernier personnage (même s'il peut rester ailleurs), de l'exclure de la correspondance ? Ce sur quoi je travaille est similaire à la recherche d'urls dans des chaînes plus larges, et j'ai besoin d'inclure les points dans le modèle mais SI le dernier caractère est un point, l'exclure comme fin de phrase.

Ainsi, dans un motif (autres url) "(/[a-zA-Z0-9._-]*) ?", existe-t-il un moyen d'exclure UNIQUEMENT la dernière période, si elle est présente ? Notez que ce qui précède serait spécifiquement les segments d'url après le domaine, mais je veux correspondre seulement à

"/some_uri/segments.php"

dans les deux

"www.domain.com/some_uri/segments.php" 

ET

"www.domain.com/some_uri/segments.php."

tout en permettant l'existence de plus d'une période dans l'uri.

Si ce qui précède n'est pas clair, imaginez que je demande un moyen d'exclure la dernière lettre d'un mot, si et seulement si c'est un "z". Ainsi, 'dozzer' et 'dozzerz' correspondent tous deux à 'dozzer' dans une structure de phrase (donc... pas de correspondance avec la position à la FIN d'une chaîne). J'ai joué avec des lookaheads et autres, mais je n'ai pas encore trouvé de solution. Je me demande si ce n'est pas possible (avec une seule regex).

Merci pour votre temps !

EDIT

Je m'excuse de ne pas avoir été plus clair, mais je dois effectuer la correspondance à l'intérieur d'un BLOC de texte. Ce que je fais, c'est parcourir le texte, trouver toutes les adresses web et leur appliquer des balises. Je ne peux donc pas utiliser d'opérateurs positionnels, tels que $, pour faire correspondre la fin de la chaîne. Ce qui a été le plus gros problème.

À moins que quelqu'un d'autre ne publie une réponse qui fonctionne après cela, je pense que je vais devoir être d'accord avec M477h3w1012 et conclure que cela ne peut pas être accompli dans la regex seule. Je vais devoir effectuer une vérification conditionnelle après avoir trouvé des correspondances pour déterminer si elles ont un point de fin. Mais je vous remercie tous, encore une fois, pour votre temps et votre aide :-)

1voto

J4Numbers Points 328

Je ne pense pas que ce soit possible dans une seule vérification regex... quelqu'un pourra peut-être me corriger sur ce point, mais je ne le pense pas pour le moment (ou alors je ne pense pas à optimiser les choses pour le moment).

Ce que vous pouvez faire, par contre, c'est faire un contrôle. Faites passer l'entrée par une fonction de remplacement initiale pour voir s'il y a ou non un point à la fin et remplacez-le s'il y en a un. À partir de là, vous pouvez simplement le faire passer par la regex précédente.

Alors voilà comment ça pourrait se passer...

function dotCheck( $url ) {
  $noDotURL = preg_replace( '/\.+$/', '', $url );
  return $noDotURL;
}

urlCheck( dotCheck( $_POST['form'] ) );

Où urlCheck est la vérification principale pour voir s'il s'agit d'une structure de liens valide ou non. La regex - sous une forme verbeuse - vérifie si les derniers caractères du lien sont des points et les supprime. Cela devrait fonctionner si quelqu'un a tapé http://www.google.com . ou http://www.google.com .....

Bonne écriture.

1voto

Adi Inbar Points 10985

Oui. En général, faites ça :

(<stuff you want to match>)(<character to exclude if at the end>)?$

Si <produits que vous voulez faire correspondre> se termine par un quantificateur, ce quantificateur doit être non gourmand afin que le dernier caractère exclu soit reconnu s'il existe.

Utilisez ensuite le premier groupe de correspondance (le $1 variable).

Cependant, je vois quelques autres problèmes avec votre regex.

  • Vous devez inclure / dans votre classe de personnage si vous souhaitez pouvoir en associer plusieurs. Sinon, vous ne faites que correspondre à partir du premier / jusqu'à juste avant la suivante.
  • Je ne suis pas sûr de savoir pourquoi vous avez un ? à la fin. Cela rend la chose entière facultative.

Cette regex accomplira ce que vous avez décrit :

(/[a-zA-Z0-9._/-]*?)(\.)?$

La variable de correspondance $1 contiendra tout ce qui commence par le premier / jusqu'à la fin, mais en excluant le point final s'il y en a un (le point sera dans l'ordre alphabétique). $2 ).

0voto

Casimir et Hippolyte Points 33449

EDIT : comme le remarque Adi Inbar, votre objectif n'est pas de faire échouer le motif mais d'exclure un caractère particulier à la fin d'une chaîne de caractères ou à la fin d'un mot :

pour exclure un 'z' à la fin d'un mot : (plusieurs 'z' à la fin sont également exclus)

avec une classe de caractères et des quantificateurs possessifs :

(?>[^\Wz]++|z++\B)+ # the most performant way

pour exclure un '.' à la fin d'une chaîne de caractères : (plusieurs '.' à la fin sont également exclus)

avec un lookahead :

^.+?(?=\.*$)

ou avec une classe de caractères et des quantificateurs possessifs :

(?>[^.]++|\.++(?!$))+

Notez que vous pouvez facilement adapter cette expression à la classe de caractères plus spécifique dont vous avez besoin, par exemple avec [\w.-] pour un uri :

$pattern = '~(?>/[\w.-]++)*/(?>[\w-]++|\.++(?!$))+/?~';

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X