Propongo questa 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]+[[:>:]])*$
È un po' lungo, ma consente una maggiore flessibilità in quanto anche quelle stringhe sono considerate "valide":
(2/2) 2new 2new
2new (2/2) 2new (2/2)
Nel codice
SELECT
*
FROM
A
WHERE
description REGEXP '^(([^2]+|[[:<:]][0-9]+/[0-9]+[[:>:]])*2([[:>:]]|[a-z])){2}([^2]+|[[:<:]][0-9]+/[0-9]+[[:>:]])*$'
Ripartizione delle espressioni regolari
La regex utilizza in realtà molte parti ripetute, ecco perché è un po' lunga:
^ # 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
$
Ripartizione dettagliata
-
#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
Un limite di parola corrisponde all'inizio e alla fine delle parole. La definizione di una parola qui è una serie di alfabeto, numeri e caratteri di sottolineatura.
[[:<:]]
è un limite di una parola di apertura e quindi corrisponde all'inizio di una parola.
[[:>:]]
è un limite di una parola di apertura e quindi corrisponde alla fine di una parola.
Il loro utilizzo qui garantisce che 2
(e le parti numeriche/numeriche) non sono circondate da altri numeri (quindi rende 21
fallire ad esempio) o contare un 2
se hai ad esempio 21/4
come uno che conta ai fini dei due 2
s nella stringa.