Je propose cette regex :
^([^2]|[[:<:]][0-9]+/[0-9]+[[:>:]])*([[:<:]]|[a-z])2([[:>:]]|[a-z])([^2]|[[:<:]][0-9]+/[0-9]+[[:>:]])+([[:<:]]|[a-z])2([[:>:]]|[a-z])([^2]|[[:<:]][0-9]+/[0-9]+[[:>:]])*$
C'est un peu long, mais cela permet une plus grande flexibilité dans la mesure où ces chaînes sont également considérées comme "valides" :
(2/2) 2new 2new
2new (2/2) 2new (2/2)
En code
SELECT
*
FROM
A
WHERE
description REGEXP '^(([^2]+|[[:<:]][0-9]+/[0-9]+[[:>:]])*2([[:>:]]|[a-z])){2}([^2]+|[[:<:]][0-9]+/[0-9]+[[:>:]])*$'
Répartition des expressions régulières
L'expression régulière utilise en fait de nombreuses parties répétitives, c'est pourquoi elle est un peu longue :
^ # Beginning of string
( # Open repeat group
([^2]+|[[:<:]][0-9]+/[0-9]+[[:>:]])* # Any characters. See #1
2 # 2
([[:>:]]|[a-z]) # Word boundary or alphabet/letter. See #2
){2} # Close repeat group and repeat 2 times
([^2]+|[[:<:]][0-9]+/[0-9]+[[:>:]])* # Any characters. See #1
$
Répartition détaillée
-
#1
( # Open group [^2]+ # Any characters except 2 | # OR [[:<:]] # Open word boundary [0-9]+ # Any numbers / # Forward slash [0-9]+ # Any numbers [[:>:]] # Close word boundary )* # Close group and repeat any number of times
-
#2
( # Open group [[:>:]] # Word boundary | # Or [a-z] # Letter/alphabet ) # Close group
Une limite de mot correspond au début et à la fin des mots. La définition d'un mot ici est une série d'alphabet, de chiffres et de caractères de soulignement.
[[:<:]]
est une limite d'ouverture de mot et correspond donc au début d'un mot.
[[:>:]]
est une limite d'ouverture de mot et correspond donc à la fin d'un mot.
Leur utilisation ici garantit que 2
(et les parties numériques/numériques) ne sont pas entourés d'autres nombres (donc fait 21
échouer par exemple) ou compter un 2
si vous avez par exemple 21/4
comme un qui compte pour les deux 2
s dans la chaîne.