Les expressions régulières dans NS-DK 12.3 

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.

regex-nsdk

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 :  

Regex : vérification de la validité
Regex-verification-validite

L’événement VERIF va 

Regex : événement VERIF

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])  :

Regex : mauvaise saisie d’un numéro de sécurité

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

 

Regex - expressions régulières

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  : 

 

Regex : checkNumSecu

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.

 

Expressions régulières

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 :  

 

Regex : données csv

On souhaite le transformer en :

 

Expressions régulières : données csv

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 :  

 

regex-checkbox

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

Philippe Litou
Philippe Litou - Ingénieur Support technique

Vous souhaitez avoir plus de renseignements sur nos produits ou nos offres ?

0Shares