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

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:

%macro wasdas(string_1=, varlist1=);

%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 &current %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:

%put HINWEIS: ergebnis: %wasdas(string_1=mpathie, varlist1=visus mpathie moedem druck);

Das Log liefert dann

HINWEIS: ergebnis: visus moedem druck

. 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 string_1=mpathie;
%let varlist1=visus mpathie moedem druck;

Wieso packen Sie den compress-Aufruf in eine Macro-Variable? Also gleich:

ergebnis=compress("&varlist1","&string_1");

Wenn Strings im Base-Code verwendet werden, dann braucht man Gänsefüßchen :

quelle="&varlist1";
raus="&string_1";

Damit sieht der Code besser, aber immer noch nicht gut aus:

data wasdas;
%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 string_1=mpathie;
%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,

%macro test(string_1=, varlist1=);
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.

%macro test (string1, varlist1);
%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:

%Macro testneu;
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,

%macro test (string1, varlist1);
%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:

225 %macro test (string1, varlist1);
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).

107 option mlogic mprint;
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.

%macro test(string1, varlist1);
%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.

%macro test (string1, varlist1);
%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:

%let liste=&varlist1;
%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 PATTERN
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