Posts Tagged ‘concatenation’

h1

La fonction CATQ pour concaténer tout en ajoutant des guillemets avec SAS 9.3 et plus

février 23, 2019

La fonction catq est disponible depuis SAS 9.3. La particularité de cette fonction est de pouvoir ajouter des guillemets simples (single quotes) ou des guillemets doubles (double quotes) autour des différentes valeurs à concaténer.

Un des avantages de la fonction catq est de pouvoir travailler autant avec les valeurs numériques qu’avec les valeurs caractères. On fera néanmoins attention aux valeurs infinies comme 1/3.

Exemple 1

data catq;
    x=catq('1' ,'ABC ',2," EFG",' ');
    put x=;

    x=catq('2' ,'ABC ',2," EFG",' ');
    put x=;
run;

Dans ce premier exemple, on voit que le 1 permet d’ajouter des guillemets simples alors que le deux permet d’ajouter des guillemets doubles. Dans le cas présent, seules les valeurs caractères ont des guillemets.

x='ABC ' 2 ' EFG' ' '
 x="ABC " 2 " EFG" " "

Exemple 2

data catq;
   x=catq('1'     ,'ABC ',2," EFG",' '); 
   put x=;

   x=catq('1a'    ,'ABC ',2," EFG",' '); 
   put x=;
 
   x=catq('1c'    ,'ABC ',2," EFG",' '); 
   put x=;
   
   x=catq('1ac'    ,'ABC ',2," EFG",' '); 
   put x=;
run;

Dans ce second exemple, on voit que la lettre a pour que toutes les valeurs soient entre guillemets, y compris les valeurs numériques.

Si on souhaite ajouter la virgule (comma) entre les différentes valeurs à concaténer avec la lettre c, il faudra impérativement garder la lettre a.

 x='ABC ' 2 ' EFG' ' '
 x='ABC ' '2' ' EFG' ' '
 x=ABC ,2, EFG,
 x='ABC ','2',' EFG',' '

Exemple 3

Une autre manière d’ajouter la virgule comme séparateur entre les valeurs est d’utiliser la lettre d (delimiter) et de préciser le séparateur dans le second argument de la fonction ; cet argument est optionnel et ne servira qu’avec la lettre d.

data catq;
   x=catq('c','ABC ',2," EFG",' '); 
   put x=;

   x=catq('d',',','ABC ',2," EFG",' '); 
   put x= /;
  
   x=catq('1ac','ABC ',2," EFG",' '); 
   put x=;

   x=catq('1ad',',','ABC ',2," EFG",' '); 
   put x=;
run;

Nous obtenons le même résultat qu’on utilise c ou d avec l’argument optionnel. La lettre d offre juste plus de possibilités.

 x=ABC ,2, EFG,
 x=ABC ,2, EFG,
 x='ABC ','2',' EFG',' '
 x='ABC ','2',' EFG',' '

Exemple 4

Lorsqu’on n’a pas besoin des guillemets autour des différentes valeurs à concaténer, la fonction catq se rapproche de la fonction catx.

data catq;  
   x=catq('d',',','ABC ',2," EFG",' '); 
   put x=/;
   
   x=catq('ds',',','ABC ',2," EFG",' '); 
   put x=;
   
   x=catx(',','ABC ',2," EFG",' ');
   put x=/;
   
   x=catq('dt',',','ABC ',2," EFG",' '); 
   put x=;
run;

Pour enlever les leading et trailing blanks avec la fonction catq, on ajoutera la lettre s (strip).
Pour uniquement enlever les trailing blanks avec la fonction catq, on ajoutera la lettre t (trim).

 x=ABC ,2, EFG,
 x=ABC,2,EFG
 x=ABC,2,EFG
 x=ABC,2, EFG

Aller plus loin

La fonction dispose d’autres arguments pour travailler avec les literals (lettre n), pour afficher les valeurs en hexadecimal (lettre x), pour utiliser une tabulation horizontale comme séparateur (lettre h), etc.
Toutes les informations sont disponibles dans la documentation en ligne : http://support.sas.com/documentation/cdl/en/lefunctionsref/63354/HTML/default/viewer.htm

À lire aussi

h1

Un texte de 32 767 caractères passé au crible

septembre 1, 2008

La quantité d’espace alloué pour une observation dans un data set SAS peut aller jusqu’à 32 767 octets (byte en anglais). Pour m’amuser, j’ai voulu tester. Pour ce faire, j’ai procédé en trois étapes :

  • J’ai créé une variable de 32 767 caractères et j’ai imprimé sa seule valeur dans un fichier .TXT.
  • Puis, j’ai voulu voir comment se déroulait le passage de 32 767 caractères d’un fichier .TXT dans une seule observation d’un data set SAS.
  • Enfin, pour visualiser le tout, j’ai imprimé cette observation dans un fichier .RTF.

Note : La longueur (length) est le mot utilisé en SAS pour parler de la quantité d’espace alloué à une observation. Seules les variables de type caractères (character) peuvent avoir jusqu’à 32 767 octets. Les variables numériques en ont, en effet, 8 au maximum.  Un octet permet de stocker un caractère d’une variable texte. Pour plus de précisions sur l’octet, reportez-vous à l’article « 9 points autour de la notion d’octet« .

Note : La longueur allouée est identique pour toutes les observations d’une même variable. Si la longueur de la variable n’est pas explicitement donné, SAS utilise la longueur de la première observation. Avec un input file, seuls 8 octets sont attribués (SAS Online Doc. : SAS Variable Attributes »). 

data one;
   input x $;
   datalines;
ABC
ABCDEFGHIJKLMN
;
run;

data two;
   x=‘ABC’;
   output;
   x=‘ABCDEFGHIJKLMN’;
   output;
run;

data three;
x=‘ABCDEFGHIJKLMN’;
output;
x=‘ABC’;
output;
run;

Dans le premier exemple, la longueur sera de 8. La seconde observation sera donc coupée.

ABC
ABCDEFGH

Dans le second exemple, la longueur est définie par la première observation. Il s’agit donc d’une longueur de 3. La seconde observation est coupée et ne garde que les trois premiers caractères.

ABC
ABC

Dans le troisème exemple, la longueur est également définie par la première observation. Elle est donc cette fois de 14. Aucune des deux observations n’est coupée.

ABCDEFGHIJKLMN
ABCDEFGHIJKLMN

Cette valeur est changeable. Il s’agit de modifier l’attribut LENGTH d’une variable donnée dans un data step. La valeur est définie soit à l’instruction LENGTH, soit à l’instruction ATTRIB.

1. Imprimer 32 767 caractères dans un fichier .TXT

Dans l’exemple ci-dessous, un fichier .TXT est créé. Il contient 32 767 caractères venant d’une seule et même observation.

Une instruction LENGTH définissant le type et la longueur de la variable : Dans cet exemple, une variable TEST_VAR est créée. Il s’agit d’une variable caractère. Une longueur de 32 767 lui est assignée avec l’instruction LENGTH. Elle pourra donc contenir jusqu’à 32 767 octets par record.

Taper plus de 32 000 caractères, c’est long mais il y a la fonction REPEAT pour nous sauver : La valeur prise par le premier record de la variable TEST_VAR est donnée. J’ai choisi de répéter la lettre a 32 766 fois. Je dis bien 32 766 fois et non 32 765 fois car la fonction REPEAT ajoute à la valeur initiale ‘a’ 32 765 autres ‘a’, soit 32 765 + 1.

Ajouter un dernier caractère à notre valeur : A ces 32 766 lettres ‘a’, j’ai ajouté la lettre ‘b’ en faisant une concaténation grâce aux deux barres verticales. De cette manière, il sera possible de visualiser l’absence de coupure faite par SAS.

filename lgth_max ‘C:/sasref/lgth_max.txt’;
data _null_;
   file lgth_max;
   length test_var $ 32767;
   test_var=repeat(‘a’,32765)||‘b’;
   put test_var;
run;

filename lgth_max clear;

Ecrire le contenu de la variable dans un fichier externe : pour écrire les 32 767 caractères dans un fichier externe, SAS a besoin de trois instructions.

  • Ecrire du texte avec l’instruction PUT : L’instruction PUT est exécutée pour chaque observation de la variable TEST_VAR, c’est-à-dire une fois dans notre cas.
  • Diriger un texte vers une autre destination que la log avec l’instruction FILE : La valeur prise par la variable TEST_VAR est écrite dans un autre fichier. Cet autre fichier est désigné de manière indirecte dans l’instruction FILE. Je dis de manière indirecte car seul un nom figure dans l’instruction FILE, un nom désignant un fichier préalablement défini. On parle de FILEREF.
  • Caractériser un fichier de destination avec l’instruction FILENAME : Le FILEREF désignant la destination du texte à imprimer est défini dans l’instruction FILENAME. A la fin du programme, ce nom servant d’intermédiaire est supprimé pour pouvoir resservir et ainsi désigner un autre fichier ou chemin d’accès.

Pas besoin de créer un data set SAS ici : Dans le cas présent, nous avons besoin d’une étape DATA pour exécuter ce code mais nous n’avons pas besoin de créer un data set. Pour épargner la tâche de création d’un data set, le nom _NULL_ remplace le nom d’un data set.

2. Créer un data set SAS

Lire les données contenues dans un fichier externe : Une variable TEST_NEW est créée dans un data set nommé TEST_DS. Elle est de type caractère comme l’indique le symbole dollar ($) présent dans l’instruction INPUT.

Avant d’entrer une valeur dans cette variable, la longueur maximale autorisée est définie dans l’instruction LENGTH. Comme il s’agit d’une variable caractère, il faut ajouter le dollar.

Au lieu de saisir manuellement les valeurs dans le data step en introduisant le mot DATALINES, une instruction INFILE désigne le fichier où sont stockées les données.

data test_ds;
   infile ‘C:/sasref/lgth_max.txt’;
   length test_new $ 32767;
   input test_new $;
run;

Vérifier la valeur prise par l’attribut LENGTH de la variable TEST_NEW :  La procédure PROC CONTENTS donnera un aperçu des caractéristiques des variables du data set TEST. Bref, cette procédure donnera accès aux méta données (metadata ou données sur les données). Cela comprend la longueur allouée à la variable TEST_NEW et le type de la variable (caractère dans ce cas précis).

proc contents data=test_ds;
run;

3. Visualiser le data set dans un fichier .RTF

Seuls les 128 premiers caractères sont imprimables dans la fenêtre OUTPUT. Par contre, vous pouvez envisager d’autres destinations comme un fichier .RTF. Dans l’exemple, on joue avec les instructions ODS (Output Delivery System).

  • D’une part, la redirection vers la fenêtre output est stoppée le temps de l’impression, via les instructions ODS LISTING.
  • D’autre part, les 32 767 caractères sont envoyés dans un fichier .RTF grâce aux instructions ODS RTF.

ods listing close;
ods rtf file=‘C:/sasref/lgth_max.rtf’;
proc print data=test_ds;
run;
ods rtf close;
ods listing;

Pours les curieux : Changez la longueur pour 32 768 et expérimentez en direct les limites de SAS.

h1

Quand compilation et exécution font la différence, un exemple

août 21, 2008

SAS effectue plusieurs lectures d’un programme. A la première lecture, c’est la compilation. A la seconde, c’est l’exécution. Connaître ces notions vous aidera à comprendre les exemples ci-dessous : pourquoi le premier code proposé ne fonctionne pas alors que les autres passent. Les fonctions PUT, VVALUE, le dictionnaire DICTIONARY.COLUMNS et le DATA _NULL_ serviront dans les exemples.

1. Un premier exemple avec la fonction PUT

Rappel sur la fonction PUT : Une fonction PUT permet de convertir une variable numérique en variable texte ou une variable texte en une autre variable texte. Elle est composée de deux paramètres. D’un côté, il y a la variable d’origine. De l’autre côté, il y a le format à appliquer sur cette variable d’origine. C’est donc la valeur sous forme formatée qui devient une valeur texte. Reportez vous à l’article « Convertir une variable caractère en numérique et inversement » pour plus de détails.

La phase de compilation : A la compilation, SAS  vérifie que la variable d’origine et le format associé sont tous les deux du même type. Il faut qu’une variable numérique est un format qui s’applique à une variable numérique. De manière identique, il faut un format caractère pour une variable texte.

La phase d’exécution : Si on ne connaît pas à l’avance le type de la variable, on peut avoir envie de définir une condition : si la variable est numérique applique tel format, sinon applique tel autre format. Hors une condition IF/THEN n’est visible par SAS qu’à la phase d’exécution.

En d’autres termes, SAS tentera d’appliquer un format numérique à une variable numérique avant de regarder si la fonction PUT est définie dans une condition.

data import_excel;
   retain type ‘CHAR’;
   study = ‘999’;
   output;
   study = ‘888’;
   output;
run;

data study_new;
   set import_excel;
   if type=‘NUM’ then study_new=put(study,best.);
   else study_new=study;
run;

Le résultat : Dans l’exemple, un format numérique (BEST.) est appliqué à une variable texte (STUDY). La première partie de la condition ne s’applique pas car le type de la variable n’est pas égal à NUM. Mais SAS cherche un format $BEST. qui n’existe pas. Il est obligé de s’arrêter là.

28 data study_new;
29 set ref;
30 if upcase(type)=’NUM’ then study_new=put(study,best.);
                                                  —–
                                                  48

ERROR 48-59: The format $BEST was not found or could not be loaded.

31 else study_new=study;
32 run;

NOTE: The SAS System stopped processing this step because of errors.
WARNING: The data set WORK.STUDY_NEW may be incomplete.
When this step was stopped there were 0 observations and 3 variables
.

Un exemple où le type de la variable est inconnu : en important un fichier EXCEL (PROC IMPORT/MIXED=YES), le type de la variable sous SAS peut-être inconnu. La variable sera caractère si une cellule contient du texte. Sinon, elle sera numérique.

2. Une solution rapide

Une fonction Vxxx: la fonction VVALUE retourne une valeur texte. Elle utilise le format associé à la variable en interne pour construire la valeur sous forme formatée. La nouvelle variable aura une longueur de 200.

data study_new;
   set ref;
   if type=’NUM’ then study_new=vvalue(study);
   else study_new=study;
run;

3. Une solution plus lourde mais pouvant s’appliquer à plusieurs variables

Une autre solution est de générer le code à exécuter. Si la variable est numérique, c’est l’instruction avec PUT qui apparaîtra, sinon c’est l’autre instruction. Cette approche fait appel à la notion de dictionnaire et de DATA _NULL_.

3.1 Créer un data set contenant le nom des variables et leur type à partir du dictionnaire (dictionary) appelé COLUMNS

La première étape consiste à créer un data set, nommé DICT_REF, contenant la variable STUDY et son type.

Choix du dictionnaire : Le dictionnaire (dictionary) COLUMNS est un data set de référence, créé de manière automatique par SAS. Il répertorie toutes les variables contenues dans tous les data sets de toutes les bibliothèques actives. Il contient donc une ligne par variable.

Chaque ligne du dictionnaire contient plusieurs informations caractérisant cette variable dont :

  • la bibliothèque d’origine (variable LIBNAME)
  • le data set d’origine (variable MEMNAME)
  • le nom de la variable (variable NAME)
  • le type de la variable (variable TYPE).

Prendre un sous-ensemble du dictionnaire : Ici seule la variable STUDY est utile. Elle provient du data set EXCEL_IMPORT sauvegardé de manière temporaire dans la bibliothèque WORK.

Mettre en majuscule : Le type de la variable est soit « num » soit « char », toujours en minuscule. Le nom de la variable peut avoir un mélange de majuscules et minuscules selon la manière dont est saisi le nom lors de sa création. Pour éviter des surprises, le nom de la variable et le type sont mis en majuscule grâce à la fonction UPCASE. L’avantage des dictionnaires, c’est qu’ils peuvent lister plus d’une variable.

proc sql;
   create table dict_ref as
      select upcase(name) as name,
             upcase(type) as type
      from dictionary.columns
      where upcase(libname) = ‘WORK’ and
            upcase(memname) = ‘EXCEL_IMPORT’ and
            upcase(name)    = ‘STUDY’;
quit;

3.2 Ecrire le code et l’appeler

La deuxième étape consiste à créer un programme nommé TMP_STUD.SAS donc le nom et l’emplacement est défini dans l’instruction FILENAME. Pour écrire dans ce fichier, l’instruction FILE est ajoutée dans le DATA _NULL_. Pour plus de précisions sur l’instruction PUT, reportez-vous à l’article « Ecrire un texte avec l’instruction PUT« .

filename stud ‘C:/sasref/tmp_stud.sas’;

data _null_;
   set dict_ref;
   file stud;
   put ‘data study_new;’;
   put @3 ‘set excel_import;’;
   if type=‘NUM’ then put @3 ‘study_new=put(‘ name ‘,9.);’;
   else put @3 ‘study_new=’ name ‘;’;
   put ‘run;’;
run;

%include stud;
filename stud;

L’écriture du programme est fonction des informations contenues dans le DICT_REF. Si plus d’une variable est sélectionnée, il faudrait préciser deux choses :

  • Les instructions DATA et SET ne sont à écrire qu’une fois. Elles sont ajoutées lors de la première boucle fait en interne autour de l’étape DATA via « if _N_=1 ».
  • L’instruction RUN apparaît une fois en fin de programme. Il faut donc l’ajouter une fois le dernier record du fichier de référence atteint. L’option END= de l’instruction SET crée une variable interne prenant la valeur 0 pour tous les records sauf le dernier où elle prend la valeur 1. La condition est donc basée sur cette variable.

filename stud ‘C:/sasref/tmp_stud.sas’;

data _null_;
   set dict_ref end=eof;
   file stud;
   if _N_=1 then
      do;
         put ‘data study_new;’;
         put @3 ‘set excel_import;’;
      end;

   if type=‘NUM’ then put @3 ‘study_new=put(‘ name ‘,9.);’;
   else put @3 ‘study_new=’ name ‘;’;
   if eof then
 put ‘run;’;
run;

%include stud;
filename stud;

Le code sauvegardé dans le fichier TMP_STUD.SAS se présente donc ainsi, vu que la variable STUDY est de type caractère.

data study_new;
   set excel_import;
   study_new=STUDY ;
run;

L’instruction %INCLUDE permet l’exécution de ce code.