String aus String entfernen
Ich möchte in einem Macro einen wechselnden String aus einem größeren entfernen und irgendwie läuft es nicht so, wie ich will.
Ich weiß, das nun folgende Beispiel ist ein wenig seltsam, aber es zeigt das Problem:
%macro test;
data wasdas;
%let string_1='mpathie';
%let varlist1='visus mpathie moedem druck';
%let liste=compress("&varlist1","&string_1");
ergebnis=&liste;
quelle=&varlist1;
raus=&string_1;
run;
%mend;
%test;
Das Ergebnis sieht dann so aus:
quelle: visus mpathie moedem druck
raus: mpathie
ergebnis: vsus od druck
Ich hätte aber gern:
quelle:visus mpathie moedem druck
raus: mpathie
ergebnis:visus moedem druck
Sorry, daß ich so viel frage! Aber bin hier Einzelkämpfer und hab niemanden, der mal kurz draufgucken kann! (Ganz schön nervig)
VG SAS-Fidi
- Anmelden oder Registrieren um Kommentare zu schreiben

Makro-Funktion
Hallo.
Es geht auch als Makro Funktion. Dabei werden im Makro nur Makro-Befehle verwendet. Dies erlaubt, dass das Makro als Funktion mit Rückgabewert aufgerufen werden kann. Sieht im Beispiel dann so aus:
%local cc current outlist;
%let cc = 1;
%let outlist =;
%do %until (%scan(&varlist1, &cc, %str( )) eq );
%let current = %scan(&varlist1, &cc, %str( ));
%if &string_1 ne ¤t %then %do;
%let outlist = &outlist ¤t;
%end;
%let cc = %eval(&cc + 1);
%end;
&outlist
%mend wasdas;
Das fehlende Semikolon am Ende hinter &OUTPUT ist beabsichtigt. Der Aufruf dieser Funktion könnte z.B. so aussehen:
Das Log liefert dann
. Der Afuruf kann aber auch in einem DATA Step oder an jeder anderen beliebigen Stelle erfolgen.
Jetzt haben Sie freie Auswahl :-)
Schöne Pfingstferien...
Macro Grundlagen
Hallo Frau Müller,
die Makro-Programmierung in SAS hat den entscheidenden Vorteil, dass man (und auch frau) viel mehr Fehler machen kann als ohne :-)))
Bei der Makro-Programmierung braucht man in der Regel die Gänsefüßchen nicht! Für die Makro-Sprache sind sowieso alles Zeichen, Character bzw. Strings. Also
%let varlist1=visus mpathie moedem druck;
Wieso packen Sie den compress-Aufruf in eine Macro-Variable? Also gleich:
Wenn Strings im Base-Code verwendet werden, dann braucht man Gänsefüßchen :
raus="&string_1";
Damit sieht der Code besser, aber immer noch nicht gut aus:
%let string_1=mpathie;
%let varlist1=visus mpathie moedem druck;
ergebnis=compress("&varlist1","&string_1");
quelle="&varlist1";
raus="&string_1";
run;
Man sollte tunlichst vermeiden die Macro-Anweisung %let in einem Data-Step zu verwenden! Das klappt zwar ohne Fehler-Meldung, aber ob das was passiert vom Programmierer genau so gewünscht wurde? In der Regel gilt: Nein!
Faust-Regel: Macro-Anweisung %let immer ausserhalb vom Data Step!
Warum macht das kleine Programm Mist? Weil die compress-Funktion keine Worte löscht, sondern Zeichen! Also jedes m, jedes p, jedes a, jedes t, jedes h, jedes i und jedes e. Wenn Sie das zu Fuß im Geist durchspielen ist sofort klar, dass Ihr Programm genau dass macht was es soll ....
Der do what I mean button fehlt bei SAS (nicht nur bei SAS).
Gruß
Hans Kneilmann, Schäfer Shop GmbH (SSI)
Lösungs-Vorschlag
Hallo,
mein Vorschlag ist:
%let varlist1=visus mpathie moedem druck;
data wasdas;
quelle="&varlist1";
raus="&string_1";
ergebnis=compress("&varlist1","&string_1");
put ergebnis= " (nicht OK)";
x=indexw(quelle,raus);
*put x=;
ergebnis=trim(substr(quelle,1,x-1)) || substr(quelle,x+length(raus));
put ergebnis= " (OK)";
run;
Gruß
Hans Kneilmann, Schäfer Shop GmbH (SSI)
Macro-Lösung
oder als Macro:
Hallo,
data wasdas;
quelle="&varlist1";
raus="&string_1";
ergebnis=compress("&varlist1","&string_1");
put ergebnis= " (nicht OK)";
x=indexw(quelle,raus);
*put x=;
ergebnis=trim(substr(quelle,1,x-1)) || substr(quelle,x+length(raus));
put ergebnis= " (OK)";
run;
%mend;
%test(string_1=mpathie, varlist1=visus mpathie moedem druck);
Gruß
Hans Kneilmann, Schäfer Shop GmbH (SSI)
prxchange
Hallo,
es geht auch mit einer Funktion.
%Let varlist2=%sysfunc(prxchange(s/&string1.//,1,&varlist1.));
data wasdas;
ergebnis = "&Varlist2.";
quelle = "&varlist1.";
raus = "&string1.";
run;
%mend;
%test(mpathie, visus mpathie moedem druck);
Schöne Grüße
Jan
Es gibt auch noch die
Es gibt auch noch die Variante sich das per Hand mit einigen Standardfunktionen selbst zusammen zubasteln:
data wasdasneu;
%let string_1="mpathie";
%let varlist1="visus mpathie moedem druck";
ergebnis1=substr(&varlist1,1,index(&varlist1,&string_1)-1); *teilstring vor dem zu entfernenden;
ergebnis2=substr(&varlist1,index(&varlist1,&string_1)+length(&string_1),length(&varlist1)-length(&string_1)-index(&varlist1,&string_1)+2); *teilstring nach dem zu entfernenden;
ergebnis=compbl(ergebnis1)||left(ergebnis2); *zusammensetzen Variante a;
ergebniss=cats(ergebnis1,' ',ergebnis2); *zusammensetzen Variante b;
quelle=&varlist1;
raus=&string_1;
run;
%mend;
%testneu;
Gruß
Chris86
Funktion tranwrd tut es auch...
Mit der Funktion tranwrd scheint mir die Lösung am einfachsten:
%put %sysfunc(tranwrd(%str( )aaa bbb ccc ddd%str( ),%str( )bbb%str( ),%str( )));
Freundliche Grüsse
Koni Kreis
%macro test (string1,
%Let varlist2=%sysfunc(prxchange(s/&string1.//,1,&varlist1.));
data wasdas;
ergebnis = "&Varlist2.";
quelle = "&varlist1.";
raus = "&string1.";
run;
%mend;
%test(mpathie, visus mpathie moedem druck);
Leider führt das zu diesem Ergebnis:
226 %Let varlist2=%sysfunc(prxchange(s/&string1.//,1,&varlist1.));
227 data wasdas;
228 ergebnis = "&Varlist2.";
229 quelle = "&varlist1.";
230 raus = "&string1.";
231 run;
232 %mend;
233 %test(mpathie, visus mpathie moedem druck);
MLOGIC(TEST): Beginning execution.
MLOGIC(TEST): Parameter STRING1 has value mpathie
MLOGIC(TEST): Parameter VARLIST1 has value visus mpathie moedem druck
MLOGIC(TEST): %LET (variable name is VARLIST2)
ERROR: A character operand was found in the %EVAL function or %IF
condition where a numeric operand is required. The condition
was: s/mpathie//
ERROR: No pattern to process.
ERROR: The regular expression passed to the function PRXCHANGE contains
a syntax error.
WARNING: Argument 1 to function PRXCHANGE referenced by the %SYSFUNC or
%QSYSFUNC macro function is out of range.
MPRINT(TEST): data wasdas;
MPRINT(TEST): ergebnis = "";
MPRINT(TEST): quelle = "visus mpathie moedem druck";
MPRINT(TEST): raus = "mpathie";
MPRINT(TEST): run;
NOTE: The data set WORK.WASDAS has 1 observations and 3 variables.
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
MLOGIC(TEST): Ending execution.
Das von mir angeführte Macro istr übriegens nur ein auf die Schnelle gestricktes Beispiel. So programmiere ich normalerweise nicht. Keine Angst!
Gruß
SAS-Fidi
Hallo SAS-Fidi, also bei mir
Hallo SAS-Fidi,
also bei mir läuft das Makro (SAS Version 9.02.02M0P011509).
108 %macro test (string1, varlist1);
109 %Let varlist2=%sysfunc(prxchange(s/&string1.//,1,&varlist1.));
110 data wasdas;
111 ergebnis = "&Varlist2.";
112 quelle = "&varlist1.";
113 raus = "&string1.";
114 run;
115 %mend;
116 %test(mpathie, visus mpathie moedem druck);
MLOGIC(TEST): Beginning execution.
MLOGIC(TEST): Parameter STRING1 has value mpathie
MLOGIC(TEST): Parameter VARLIST1 has value visus mpathie moedem druck
MLOGIC(TEST): %LET (variable name is VARLIST2)
MPRINT(TEST): data wasdas;
MPRINT(TEST): ergebnis = "visus moedem druck";
MPRINT(TEST): quelle = "visus mpathie moedem druck";
MPRINT(TEST): raus = "mpathie";
MPRINT(TEST): run;
NOTE: The data set WORK.WASDAS has 1 observations and 3 variables.
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
MLOGIC(TEST): Ending execution.
Vielleicht hilft es ja, die Parameter mit %str() zu klammern.
%sysfunc(prxchange(%STR(s/ &string1. / /),1,%str(&varlist1.)))
%mend test;
%PUT %test(mpathie, visus mpathie moedem druck);
295 %macro test(string1, varlist1);
296 %sysfunc(prxchange(%STR(s/ &string1. / /),1,%str(&varlist1.)))
297 %mend test;
298 %PUT %test(mpathie, visus mpathie moedem druck);
MLOGIC(TEST): Beginning execution.
MLOGIC(TEST): Parameter STRING1 has value mpathie
MLOGIC(TEST): Parameter VARLIST1 has value visus mpathie moedem druck
MLOGIC(TEST): Ending execution.
visus moedem druck
Oder statt den regulären Ausdruck direkt anzugeben, erst einmal den regulären Ausdruck zu kompilieren.
%local pattern;
%local regtext;
%Let Regtext=%str(s/ &string1. / /);
%let Pattern = %sysfunc(prxparse(&Regtext.));
%IF &Pattern. NE . %THEN %DO;
%sysfunc(prxchange(&Pattern.,1,%str(&varlist1.)))
%END;
%ELSE %DO;
%PUT ERROR: Regulärer Ausdruck "&RegText." enthält Fehler;
%ABORT ;
%END;
%mend;
%PUT %test(mpathie, visus mpathie moedem druck);
299 %macro test (string1, varlist1);
300 %local pattern;
301 %local regtext;
302 %Let Regtext=%str(s/ &string1. / /);
303 %let Pattern = %sysfunc(prxparse(&Regtext.));
304 %IF &Pattern. NE . %THEN %DO;
305 %sysfunc(prxchange(&Pattern.,1,%str(&varlist1.)))
306 %END;
307 %ELSE %DO;
308 %PUT ERROR: Regulärer Ausdruck "&RegText." enthält Fehler;
309 %ABORT ;
310 %END;
311 %mend;
312 %PUT %test(mpathie, visus mpathie moedem druck);
MLOGIC(TEST): Beginning execution.
MLOGIC(TEST): Parameter STRING1 has value mpathie
MLOGIC(TEST): Parameter VARLIST1 has value visus mpathie moedem druck
MLOGIC(TEST): %LOCAL PATTERN
MLOGIC(TEST): %LOCAL REGTEXT
MLOGIC(TEST): %LET (variable name is REGTEXT)
MLOGIC(TEST): %LET (variable name is PATTERN)
MLOGIC(TEST): %IF condition &Pattern. NE . is TRUE
MLOGIC(TEST): Ending execution.
visus moedem druck
Schöne Grüße
Jan
Die zweite Variante läuft,
Die zweite Variante läuft, die erste leider auch nicht.
Vielleicht liegt es daran, daß ich nochj mit 9.1.3 arbeite.
Danke!
VG SAS-Fidi
Leider stellt sich nun erst
Leider stellt sich nun erst nach einiger Zeit herraus, daß das Ganze doch nicht fehlerfrei arbeitet.
So sieht der entsprechende Macroteil aus:
%local pattern;
%local regtext;
%Let raus=%str(s/ string&eb_1.&dot_1. / /);
%let Pattern = %sysfunc(prxparse(&Raus.));
%IF &Pattern. NE . %THEN %DO; %sysfunc(prxchange(&Pattern.,1,%str(&liste.))); %END;
Das führt zu folgender Felermeldung:
MLOGIC(EBENE): %LOCAL REGTEXT
MLOGIC(EBENE): %LET (variable name is RAUS)
MLOGIC(EBENE): %LET (variable name is PATTERN)
MLOGIC(EBENE): %IF condition &Pattern. NE . is TRUE
MPRINT(EBENE): visuscale hba1c ydiab typdiab hypscale fette niere alter
nikotin bmiscale durchblut herzinf apoplex makula sysdruck diasdruck;
ERROR 180-322: Statement is not valid or it is used out of proper order.
MLOGIC(EBENE): %IF condition (&ebene=1 and &z=1) is FALSE
NOTE: Line generated by the macro function "SYSFUNC".
1 visuscale hba1c ydiab typdiab hypscale fette niere alter nikotin
---------
180
1 ! bmiscale durchblut herzinf apoplex makula sysdruck diasdruck
MLOGIC(EBENE): %IF condition (&ebene=1 and &z=2) is FALSE
MLOGIC(EBENE): %IF condition &stop ne 1 is FALSE
MLOGIC(EBENE): %GLOBAL NODE&EBENE.&Z
MLOGIC(EBENE): %LET (variable name is NODE38)
MLOGIC(EBENE): %DO loop index variable Z is now 9; loop will not iterate
again.
MLOGIC(EBENE): Ending execution.
ERROR 180-322: Statement is not valid or it is used out of proper order.
Das Programm arbeitet aber trotzdem richtig. Woran kann das liegen?
VG SAS-Fidi
Bin wieder einmal über dieses
Bin wieder einmal über dieses Problem gestolpert. Das Programm arbeitet zwar einwandfrei, aber diese Fehlermeldung erhalte ich immer noch. Hab immer noch keine Ahnung warum.
Kann mir wirklich niemand helfen?
VG SAS-Fidi
Schade ......... VG SAS-Fidi
Schade .........
VG SAS-Fidi
lauffähiges Beispiel
Hallo Frau Müller,
um helfen zu können ist ein vollständiges lauffähiges Beispiel nötig. Mit allen Hilfs- und unter-Macros!
Ich muß hier bei mir den Fehler nachstellen können. Alles andere ist nur Kaffessatz-Leserei.
Ich denke, dass geht allen so, deshalb kam m.E. auch keine Reaktion auf den Hilfe-Ruf vom 09.03.2011.
Gruß
Hans Kneilmann, Schäfer Shop GmbH (SSI)
Danke, ich konnte das
Danke,
ich konnte das Problem mittlerweile doch selbst lösen.
Es ist im Endeffekt genauso, wie SAS es ins Log schreibt! Die Anweisung %sysfunc(prxchange(&Pattern.,1,%str(&liste.))); führt dazu, daß dort steht: visuscale hba1c ydiab typdiab hypscale fette niere alter nikotin.... SAS weiß dann einfach nicht, was es damit anfangen soll. Der Text wird so nicht automatisch in eine neue Variable geschrieben. Richtig muß es heißen:
%let uebrig=%sysfunc(prxchange(&Pattern.,1,%str(&liste.)));
VG SAS-Fidi