Aide REGEXP pourtant simple

Aide REGEXP pourtant simple - Divers - Programmation

Marsh Posté le 27-10-2021 à 11:42:56    

Hello,
J'ai écrit une regexp, elle fonctionne... presque
Règle : ne doit pas commencer par un tiret et ne doit pas se terminer par un tiret
 
Elle est plus complexe que ça, en réalité il y a une liste de caractères interdits en début de chaine et une autre liste de caractères interdits en fin de chaines mais le problème reste le même.
Cette regexp fonctionne correctement SAUF s'il n'y a qu'un seul caractère.  

Code :
  1. ^[^-].*[^-]$


Résultats:

Code :
  1. a => ko (devrait être ok !)
  2. a- => ko (résultat attendu)
  3. -a- => ko (résultat attendu)
  4. - => ko (résultat attendu)
  5. aa => ok (résultat attendu)
  6. azdeazdadad-azeaze => ok (résultat attendu)


Où est le problème? normalement le point signifie n'importe quel caractère donc suivi par une étoile, cela devrait matcher s'il n'y a qu'1 seul caractère non...?

Reply

Marsh Posté le 27-10-2021 à 11:42:56   

Reply

Marsh Posté le 27-10-2021 à 12:34:14    

Le second "[^-]" rend la saisie d'un caractère autre que "-" obligatoire. Par conséquent, entre ça et le ".*" précédent, tu dois saisir au minimum 2 caractères pour que ta regex fonctionne.

 

Tu peux donc virer la fin de ta regex qui devient juste :

 
Code :
  1. ^[^-]*$


Message édité par Harkonnen le 27-10-2021 à 12:36:03

---------------
J'ai un string dans l'array (Paris Hilton)
Reply

Marsh Posté le 27-10-2021 à 13:09:08    

Merci de ta réponse mais cela ne fonctionne pas
https://regex101.com/r/ZpXmGD/1
la première ligne doit passer ainsi que les 4 dernières


Message édité par jeromax le 27-10-2021 à 13:12:31
Reply

Marsh Posté le 27-10-2021 à 14:33:15    

Je ne sais pas si c'est pertinent mais y'a des fonctions dans le plupart des langages bcps moins couteuse en temps machine que de faire une regex.
 
Pourquoi ne pas comparer la longueur de ta chaine avant et après un trim des tiret par exemple, ou tester le 1er et le dernier caractère, car là tu t'embarques dans une regex alors que résultat vide est bon, ça me semble un peu overkill...


---------------
D3
Reply

Marsh Posté le 27-10-2021 à 14:35:18    

C'est ce que j'ai fait oui :D  
j'ai gardé ma regexp et ajouté une condition au cas où il n'y a qu'un seul caractere. D'ailleurs c'est probablement plus maintenable qu'une regexp de 12km de long...

Reply

Marsh Posté le 28-10-2021 à 12:50:00    

jeromax a écrit :


Règle : ne doit pas commencer par un tiret et ne doit pas se terminer par un tiret
...

Code :
  1. ^[^-].*[^-]$




 
Peut être avec quelque chose comme ca ?
 

Code :
  1. (^[^-].*|.*[^-]$)


 
A paufiner un peu surement parce que j'ai un doute sur la syntaxe exacte mais l'idée est là.


Message édité par kisscoolz le 28-10-2021 à 12:50:36

---------------
http://lacabanedeladmin.trickip.net/
Reply

Marsh Posté le 28-10-2021 à 20:39:45    

Code :
  1. ^[^-]?[^-]*[^-]?$


Et cela ?


---------------
C'est en écrivant n'importe quoi qu'on devient n'importe qui.
Reply

Marsh Posté le 29-10-2021 à 09:48:05    

Marche pas, ça ne matche pas azdeazdadad-azeaze :D

 

La question est mal posée côté exemples mais je pense qu'il veut matcher :

aa
a
azdeazdadad-azeaze

 

Et rejeter :

a-
-a-
-

 

A confirmer.

 

C'est vrai que ça semble trivial mais quand tu testes ben ça l'est pas :o
Ou alors il faut tricher un peu et mettre du | à défaut d'arriver à exprimer le truc en un coup.

Message cité 2 fois
Message édité par TotalRecall le 29-10-2021 à 09:50:29

---------------
Réalisation amplis classe D / T      Topic .Net - C# @ Prog
Reply

Marsh Posté le 29-10-2021 à 10:02:52    

TotalRecall a écrit :

Marche pas, ça ne matche pas azdeazdadad-azeaze :D
 
La question est mal posée côté exemples mais je pense qu'il veut matcher :

aa
a
azdeazdadad-azeaze


 
Et rejeter :

a-
-a-
-


 
A confirmer.


Non, non c'est bien ce que j'avais compris aussi, j'ai juste oublié de prendre en compte sa dernière ligne, je me suis focalisé sur pas de tiret au début, pas de tiret à la fin et possibilité d'un seul caractère sans penser au cas où le tiret est au milieu.


---------------
C'est en écrivant n'importe quoi qu'on devient n'importe qui.
Reply

Marsh Posté le 29-10-2021 à 11:13:56    

TotalRecall a écrit :

Marche pas, ça ne matche pas azdeazdadad-azeaze :D
 
La question est mal posée côté exemples mais je pense qu'il veut matcher :

aa
a
azdeazdadad-azeaze


 
Et rejeter :

a-
-a-
-


 
A confirmer.
 
C'est vrai que ça semble trivial mais quand tu testes ben ça l'est pas :o
Ou alors il faut tricher un peu et mettre du | à défaut d'arriver à exprimer le truc en un coup.


Oui c'est ça :-)

Reply

Marsh Posté le 29-10-2021 à 11:13:56   

Reply

Marsh Posté le 29-10-2021 à 11:41:59    

J'aurai plutot vu :
 
 

Code :
  1. ^[^-]?.*[^-]$


 
D'ailleurs dans le lien vers regex101 que tu as mis, le retour à la ligne de la ligne 5 (celle ou il y a rien) fou la merde, si tu l'enleve ma regex pass bien, si tu la remets ca remerde. Je ne sais pas si c'est un bug du site.
 
Pour être plus précis, des que tu fais un retour à la ligne sans rien, la ligne du dessus se met à matcher sans raison.


Message édité par reroll le 29-10-2021 à 11:48:17
Reply

Marsh Posté le 29-10-2021 à 14:08:04    

Ah ouais bien vu, c'est assez déroutant.
 
Par contre ta regex matche aussi :
-a
Dont je ne sais pas si c'est admissible ou pas vu que le 1er post n'en dit rien, comme je disais le jeu d'exemple est insuffisant.


---------------
Réalisation amplis classe D / T      Topic .Net - C# @ Prog
Reply

Marsh Posté le 29-10-2021 à 14:15:29    

Bien vu pour le -a, vu que c'est pas dans le poste initial, je n'ai pas testé.

Reply

Marsh Posté le 29-10-2021 à 14:35:12    

La règle est : ne doit pas commencer par un tiret et ne doit pas se terminer par un tiret (quelque soit le nombre de caractères)
Merci beaucoup de vous pencher sur le sujet!

Reply

Marsh Posté le 29-10-2021 à 14:46:33    

Sauf que même comme ça c'est ambigu, d'où la nécessité de fournir un vrai jeu de validation. Un truc formel qui ne laisse aucune place à l'interprétation, et directement copiable dans un outil genre regex101.

 

Parce qu'en français et en informatique les opérateurs logiques ont une fâcheuse tendance à ne pas avoir le même sens.

 

"ne doit pas commencer par un tiret et ne doit pas se terminer par un tiret" ça peut vouloir dire qu'on accepte TOUT, sauf ce qui commence et finit en même temps par un tiret.
Mais également qu'on accepte ce qui ne commence par par un tiret, mais aussi ce qui ne finit par par un tiret.
Edit : en me relisant je pense que j'ai écrit une connerie mais vous saisissez le propos [:ddr555]

 

Et on ne sait pas si c'est un devoir scolaire (auquel cas on va lever un peu le pied :o) ou un truc qui sert un besoin réel...


Message édité par TotalRecall le 29-10-2021 à 14:49:23

---------------
Réalisation amplis classe D / T      Topic .Net - C# @ Prog
Reply

Marsh Posté le 29-10-2021 à 15:36:53    

Effectivement, c'est mieux comme ça : ne doit pas commencer par un tiret OU ne doit pas se terminer par un tiret (tout autre caractère est autorisé)
-aaa ne doit pas passer
aaa- ne doit pas passer
-aaa- ne doit pas passer
aaa doit passer
a doit passer
aaa-a doit passer
aaa-a-aa doit passer
 
Pour le moment j'ai utilisé ma regex du début et testé en plus que le mot n'est pas un tiret lorsque sa longueur est 1  
Et c'est un vrai besoin d'entreprise :jap:  

Reply

Marsh Posté le 29-10-2021 à 15:46:23    

Je vais être encore un peu plus pointilleux dans l'énoncé, mais j'imagine que c'est "ne doit pas commencer ou terminer par UN OU PLUSIEURS tiret" donc en gros
 
--aa / aa-- et --aa-- ne doivent pas matcher non plus ?
 
Ou en plus français : Le premier et le dernier caractère de la chaîne ne peuvent pas être un tiret "-".


Message édité par reroll le 29-10-2021 à 15:47:49
Reply

Marsh Posté le 29-10-2021 à 15:48:45    

oui, tant qu'il y a un tiret au début ou à la fin, cela ne doit pas matcher

Reply

Marsh Posté le 29-10-2021 à 16:08:22    

Celui semble être le bon :  
 
v1

Code :
  1. ^(?![-]).*[^-]$


 
v2

Code :
  1. ^(?![-\s]).*[^-]$


 
Celui du v2 exclu les whitespaces en début de chaine, donc ca exclu les ligne vides et les chaines commençant avec un espace ou une tabulation.
 
Pour être sur je l'ai testé sur tout ça .
 
-a
--a
-aa
aa-
--aa
aa--
aa--aa
aa--aa--
--aa--aa
--aa--aa--
--aa--
aa--aa--aa
 
 
Et je confirme le bug sur le site regex101 du coup je suis passé par https://regexr.com/ qui semble plus fiable.


Message édité par reroll le 29-10-2021 à 16:31:28
Reply

Marsh Posté le 29-10-2021 à 16:31:49    

Joli ! !
Cela semble fonctionner en effet.
Merci beaucoup  :jap:

Reply

Marsh Posté le 29-10-2021 à 16:55:56    

Pas mal le negative lookahead de ce qu'on ne veut pas, même si comme disait mechkurt c'est pas dément tout ça niveau perfs :D


---------------
Réalisation amplis classe D / T      Topic .Net - C# @ Prog
Reply

Marsh Posté le 29-10-2021 à 18:05:53    

Clairement, je n'utiliserai les regex que pour des pattern complexes qui nécessiteraient trop de lignes de code pour un équivalent avec des opérations sur les String.

Reply

Marsh Posté le 30-10-2021 à 01:03:52    

jeromax a écrit :

Hello,
J'ai écrit une regexp, elle fonctionne... presque
Règle : ne doit pas commencer par un tiret et ne doit pas se terminer par un tiret
 
Elle est plus complexe que ça, en réalité il y a une liste de caractères interdits en début de chaine et une autre liste de caractères interdits en fin de chaines mais le problème reste le même.
Cette regexp fonctionne correctement SAUF s'il n'y a qu'un seul caractère.  

Code :
  1. ^[^-].*[^-]$


Résultats:

Code :
  1. a => ko (devrait être ok !)
  2. a- => ko (résultat attendu)
  3. -a- => ko (résultat attendu)
  4. - => ko (résultat attendu)
  5. aa => ok (résultat attendu)
  6. azdeazdadad-azeaze => ok (résultat attendu)


Où est le problème? normalement le point signifie n'importe quel caractère donc suivi par une étoile, cela devrait matcher s'il n'y a qu'1 seul caractère non...?


Le problème est évident :
Chacun des [^-] de ton expression vaut un caractère. Ton expression doit donc avoir au moins deux caractères.
La corriger est donc simplissime :
^[^-](.*[^-])?$
ou mieux, en évitant de faire un capturing group inutile
^[^-](?:.*[^-])?$
Et pas besoin de lookahead pour cela
 
Par contre, si tu as deux listes différentes pour le début et la fin (au vu de ton post) ça complique un poil les choses :
si abc représente la liste des caractères interdits au début et xyz celle de ceux interdits à la fin, il faudra faire ainsi :  
^[^abcxyz]|[^abc].*[^xyz]$ avec éventuellement simplification du premier terme s'il y a des caractères interdits communs a la liste du début et celle de fin.
^[^abcxyz]$|^[^abc].*[^xyz]$ avec éventuellement simplification du premier terme s'il y a des caractères interdits communs a la liste du début et celle de fin.
 
A+,


Message édité par gilou le 02-11-2021 à 11:16:16

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 30-10-2021 à 09:55:10    

Cela rejoint un peu Gilou mais en plus clair je pense, il suffit de supposer les deux cas :
- 1 seul caractère
- plusieurs caractères

 

Dans cet exemple, ça ne doit pas commencer par un "0" ou finir par un "a" (je nettoie les retours chariots pour le multi-ligne) :

 

^[^a0\r\n]$|^[^0\r\n]+[^a\r\n]+$

 

Ainsi en première partie (^[^a0\r\n]$) on retrouve le cas d'un seul caractère et donc l'union de tous les caractères par lesquels on ne veut pas que ça commence ou finisse ("0" et "a", ainsi que les retours chariots).
Dans la seconde partie (^[^0\r\n]+[^a\r\n]+$) on demande que ça ne commence par au moins un des caractères interdits en début ("0" ainsi que les retours chariots : ^[^0\r\n]+) et que ça ne finisse pas par au moins un des caractères interdits en fin ("a" ainsi que les retours chariots : [^a\r\n]+$).

 

https://regex101.com/r/soW12S/1

  

EDIT : cela rejoint complètement l'idée de Gilou en fait, simplement il y avait quelques corrections à apporter, dans la première partie il faut bien spécifier le $ et après dans la seconde partie pas besoin de spécifier "possiblement n'importe quel caractère" en utilisant le bons quantifiers sur les deux autres sous-groupes.


Message édité par MaybeEijOrNot le 30-10-2021 à 10:03:41

---------------
C'est en écrivant n'importe quoi qu'on devient n'importe qui.
Reply

Marsh Posté le 02-11-2021 à 10:57:11    

Tu as raison, quand j'ai écrit ^[^abcxyz]|[^abc].*[^xyz]$ j'avais bien sur en tête ^(?:[^abcxyz]|[^abc].*[^xyz])$  
Soit ^[^abcxyz]$|^[^abc].*[^xyz]$ si on n'a pas envie d’écrire de groupe, même non capturant
Mais effectivement, je ne connais pas les règles de précédence pour ^ et $ et ça faussait peut-être l'expression initiale.
EDIT : ^ et $ sont au 3e niveau, tandis que | est au 4e et dernier (par construction, | a toujours le plus bas niveau, plus bas que pour tout autre élément d'une regexp, bref, c'est le dissociateur ultime), donc ^a|b$ c'est pas ^a$|^b$ et mon expression initiale était fausse.
A+,


Message édité par gilou le 02-11-2021 à 11:17:30

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 08-11-2021 à 10:24:14    

Rhooo merci à tous pour vos messages.
j'utilise maintenant ^(?![-\\s\']).*[^-\\s]$ et elle fonctionne parfaitement pour mes règles de gestion (et donc mes cas JUnit)

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed