Les expressions régulières dans NS-DK 12.3
- 29 septembre 2025
- Envoyé par : LaetitiaB
- Catégorie: Technologie

Cet article fait suite à notre première présentation des expressions régulières/regex (Consulter l’article) et a pour objectif de passer de la théorie à la pratique.
Après avoir découvert leurs principes et leurs principaux cas d’usage, nous allons maintenant les mettre en œuvre concrètement dans NS-DK.
Pour illustrer l’intégration des regex, nous allons construire une petite application de gestion de patients.
Chaque enregistrement contiendra un prénom, un nom et un numéro de sécurité sociale.
L’utilisation de regex permettra de valider et contrôler automatiquement la qualité des données saisies, en évitant les erreurs courantes de format.
À noter que les mécanismes présentés ici s’appliquent également à NatStar, qui implémente les regex de manière identique.

La fenêtre ci-dessus permet de saisir l’insérer des patients dans la liste. Cette liste sera sauvegardée dans un fichier.
Chaque champ de saisie est associé à une regex. Si le contenu du champ n’est pas conforme à sa regex, il apparait en rouge. Ce mécanisme illustre le cas d’usage sur la validité des champs de saisie.
Le bouton Modifier… ouvre une deuxième fenêtre qui permet de modifier les informations :
- si le mois est spécifié sur un chiffre, un zéro sera placé devant
- le sexe 1 ou 2 sera remplacé par homme ou femme.
On pourra modifier l’un de ces données ou les deux en coquant les checkbox.
Cas d’usage : vérification de la validité
Il s’agit ici d’utiliser les regex pour vérifier que le contenu d’un entry-field est correct.
Le contrôle du contenu des champs doit être fait chaque fois que la valeur des champs change : on peut contraliser ce contrôle dans un événement (à créer) de la fenêtre nommé VERIF. Chaque événement CHANGED déclenche cet événement en lui envoyant son propre identifiant de telle manière à ce que VERIF sache quel est le contrôle à vérifier.
=> Coder ceci dans le CHANGED des trois entry-fields :


L’événement VERIF va

La fonction checkNumSecu est à créer dans une librairie. Elle permet de vérifier par une regex que son paramètre est conforme à un numéro de sécurité sociale puis elle vérifie que les deux derniers chiffres (la clé) sont cohérents par rapport aux 13 premiers.
La function retourne une instance de segment NUMSECU_SG qui contient les différents champs d’un numéro de sécurité sociale. Si le numéro est invalide elle renvoie #null.
Cette fonction va récupérer chaque partie du numéro de sécurité sociale et illustre ainsi le 2è cas d’usage des expressions régulières : l’extraction de données.
Pour faciliter tant le contrôle que l’extraction, on va générer une regex contenu 7 groupes capturant nommés. Ils permettent aussi une lecture plus facile de la regex qui pourrait devenir indigeste. Un numéro de sécurité sociale en France métropolitaine est en effet constitué de 7 parties :
- Le sexe sur un chiffre (on se limitera ici à 1 ou 2)
- L’année de naissance sur 2 chiffres
- Le mois de naissance sur 2 chiffres
- Le département de naissance sur 2 caractères
- Le numéro de la commune de naissance (département + commune forment le code insee de la commune)
- L’index : le numéro de naissance dans le mois pour cette commune
- La clé (sur 2 chiffres) qui est calculée à partir des treize premiers caractères
function checkNumSecu(dynstr numSecu$) return NUMSECU_SG@
local NUMSECU_SG@ numSecu
local dynstr regex$
local nsrgx_code@ reg, NSRGX_Error err, nsrgx_match_data@ match
local resultat%, err$, integer err%
local dynstr valeur$ ;** dynstr obligatoire, pas cstring sinon nsrgx_match% retourne -29
local numsecu%(8), numSecu2$(15)
local cle_theorique%(1)
@reg = #null
@match = #null
@numSecu = #null
resultat% = 1
err$ = ""
err% = 0
valeur$ = ""
;** vérification des paramètres
if length numSecu$ <> 15
resultat% = -1
err$ = "longueur incorrecte"
else
regex$ = "^(?P<sexe>[12])(?P<annee>[0-9]{2})(?P<mois>0[1-9]|1[0-2])(?P<dept>2[AB]|0[1-9]|2[1-9]|[3-9][0-9])(?P<commune>[0-9]{3})(?P<index>[0-9]{3})(?P<cle>[0-9]{2})$"
@reg = nsrgx_compile(regex$, 0, err)
if @reg <> #null
@match = nsrgx_create_match_data_from_pattern(reg)
if @match <> #null
resultat% = nsrgx_match%(reg, numSecu$, 0, 0, match)
if resultat% > 0
new @numSecu
numsecu.sexe% = nsrgx_get_substring_byname$(match, "sexe", err%)
numsecu.annee$ = nsrgx_get_substring_byname$(match, "annee", err%)
numsecu.mois$ = nsrgx_get_substring_byname$(match, "mois", err%)
numsecu.dept$ = nsrgx_get_substring_byname$(match, "dept", err%)
numsecu.commune$ = nsrgx_get_substring_byname$(match, "commune", err%)
numsecu.index$ = nsrgx_get_substring_byname$(match, "index", err%)
numsecu.cle% = nsrgx_get_substring_byname$(match, "cle", err%)
evaluate upcase numsecu.dept$
where "2A"
numSecu.DEPT% = 19
endwhere
where "2B"
numSecu.DEPT% = 18
endwhere
else
numSecu.DEPT% = numSecu.DEPT$
endevaluate
endif
endif
endif
err$ = nsrgx_ErrMsg$(resultat%)
endif
if @reg <> #null
nsrgx_dispose_code reg
endif
if @match <> #null
nsrgx_dispose_match_data match
endif
;** fin de contrôle des paramètres
if resultat% > 0 ;** on vérifie la clé
numsecu2$ = numsecu.sexe% & numsecu.annee$ & numsecu.mois$ & numsecu.dept% & \
numsecu.commune$ & numsecu.index$
numsecu% = numsecu2$
cle_theorique% = 97 - (numsecu% % 97)
if cle_theorique% <> numSecu.cle% ;** la clé saisie n’est pas la bonne
dispose @numsecu
@numsecu = #null
endif
endif
return numSecu
endfunction
Voici le résultat d’une mauvaise saisie d’un numéro de sécu (le mois 18 n’existe pas, il n’est pas conforme au morceau de la regex 0[1-9]|1[0-2]) :

Si on remplace le mois 18 par 08, le champ est noir : contenu correct .

Le bouton insérer place les informations du patient à partir du résultat de la fonction checkNumSecu qui a déjà récupéré les différents composants du numéro de sécurité sociale :

Les boutons sauvegarder et Charger permettent respectivement de crée un fichier dont le contenu est celui de la liste et inversement d’afficher dans la liste le contenu du fichier.

Le bouton modifier… va permettre de modifier la présentation des colonnes sexe et/ou mois de la liste.
Si jamais le fichier de donné a été modifié en dehors de l’application, il est possible de trouver un mois avec un seul chiffre. La modification permet alors de placer un 0 pour les mois stockés sur un seul chiffre.
Par exemple on part du fichier donnes.csv suivant :

On souhaite le transformer en :

Dans l’INIT de la 2e fenêtre, on récupère le nom du fichier et le pointeur de la fenêtre mère :

Dans le bouton modifier on va opérer les transformations sélectionnées par les checkbox :
local control LISTE, fichier$, h%, dynstr ligne$, i%
local dynstr regexH$, dynstr regexF$, dynstr regexMois$
local nsrgx_code@ regH, nsrgx_code@ regF, nsrgx_code@ regMois
local NSRGX_Error err
local nsrgx_match_data@ matchH, nsrgx_match_data@ matchF, nsrgx_match_data@ matchMois
local resultat%, err$
local dynstr valeur$ ;** dynstr obligatoire, pas cstring
local dynstr resultat$
;** initialisation des variables
fichier$ = ST_NOM_FICHIER
@regMois = #null
@regH = #null
@regF = #null
@matchF = #null
@matchH = #null
@matchMois = #null
resultat% = 1
err$ = ""
valeur$ = ""
resultat$ = ""
@LISTE = FORMULAIRE(getdata%).STV_PATIENTS
;** ouverture du fichier
h% = t_open%(fichier$)
if h% = 0 or t_error% <> 0
resultat% = -1
message "erreur", "impossible d'ouvrir le fichier " & fichier$
endif
;**dans cette version de NS-DK on ne peut pas effectuer de remplacement conditionnel : on va donc devoir créer deux transformation pour le sexe : remplacer 1 par homme puis remplacer 2 par femme
if CHK_SEXE and resultat% = 1
;** préparation des regex sexe
regexH$ = "^(?P<sexe>1),(?P<suite>.*)"
regexF$ = "^(?P<sexe>2),(?P<suite>.*)"
@regH = nsrgx_compile(regexH$, 0 , err)
@regF = nsrgx_compile(regexF$, 0 , err)
if @regH <> #null and @regF <> #null
NSLogInfo c_log$, "les regex " & regexH$ & " et " & regexF$ & " sont bien compilables"
@matchH = nsrgx_create_match_data_from_pattern(regH)
if @matchH = #null
resultat% = -1
endif
@matchF = nsrgx_create_match_data_from_pattern(regF)
if @matchF = #null
resultat% = -1
endif
else
resultat% = -1
endif
endif
if CHK_MOIS and resultat% = 1
;** préparation de la regex mois. Ici on s’intéresse uniquement au mois : on l’isole du reste
;** on s’intéresse ici aux mois sur un chiffre et non sur deux chiffres afin de les préfixer par 0
;** on spécifie donc (?P<mois>[0-9]) et non (?P<mois>[0-9]{1, 2})
regexMois$ = "^(?P<debut>(\w+,){5})(?P<mois>[0-9]),(?P<suite>(.*))"
@regMois = nsrgx_compile(regexMois$, 0 , err)
if @regMois <> #null
@matchMois = nsrgx_create_match_data_from_pattern(regMois)
if @matchMois = #null
resultat% = -1
endif
else
resultat% = -1
endif
endif
if resultat% = 1
i% = 0
while not t_eof%(h%)
ligne$ = t_readlnEx$(h%)
if CHK_SEXE
;** on remplace la valeur du groupe capturant nommé suite par homme quand on a détecté 1 dans sexe
resultat% = nsrgx_replace%(regH, ligne$, 0, NSRGX_SUBSTITUTE_GLOBAL%, matchH, "homme,${suite}",\
resultat$)
if ligne$ = resultat$ ;** match non trouvé : il s’agit d’une femme. On remplace le sexe par femme
resultat% = nsrgx_replace%(regF, ligne$, 0, NSRGX_SUBSTITUTE_GLOBAL%, matchF, "femme,${suite}",\
resultat$)
endif
LISTE[i%] = resultat$
ligne$ = resultat$ ;** pour la gestion des mois ci-dessous, on part de ce résultat
endif
if CHK_MOIS
resultat% = nsrgx_replace%(regMois, ligne$, 0, NSRGX_SUBSTITUTE_GLOBAL%, matchMois,\
"${debut}0${mois},${suite}", resultat$)
LISTE[i%] = resultat$
endif
i% = i% + 1
endwhile
endif
if h% <> 0
t_close h%
endif
;** Libération de la mémoire (extrait)
if @regMois <> #null
nsrgx_dispose_code regMois
endif
if @matchH <> #null
nsrgx_dispose_match_data matchH
endif
;** etc.
Auteur
