- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
I want to change the special characters using this code.
It's remain to define the size of observation.
the function length does not work
could you, please, help me?
%macro tt();
data test1;
set test;
%do i=1 %to %sysfunc(length(var));
lettre=substr(var,&i.,1);
type=indexc(lettre,'3A3B3C'x);
if type then do; substr(var,&i.,1)=translate(lettre,'414243'x,'3A3B3C'x);
end;
else do; substr(var,&i.,1)=lettre;
end;
%end;
run;
%mend;
%tt;
Whith this method, the code work correctely
data test1;
set test;
var1=translate(var,'ABC','3A3B3C'x);
run;
NB: these are tests that I do for myself
Thank you
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Note that your whole "experimental" logic can be solved without any macro code at all in one simple data step:
data test;
length var $10.;
var = 'test;;:ii<';
output;
var = 'testj;;';
output;
run;
data test1;
set test;
do i = 1 to length(var);
lettre = substr(var,i,1);
type = indexc(lettre,'3A3B3C'x);
if type
then do;
substr(var,i,1)=translate(lettre,'414243'x,'3A3B3C'x);
end;
else do;
substr(var,i,1) = lettre;
end;
end;
run;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Use
options mprint mlogic symbolgen;
before executing the macro, read the log after execution.
The statement
%sysfunc(length(var))
will always return 3, because you don't get the length of the contents of "var", but the length of the text "var".
The docs have an interesting chapter about macros.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
What are you trying to accomplish?
Do you have characters in column Var that you want to remove?
If yes, you don't need a macro for that, just keep your data step.
Do you want to translate the individual characters, ie. one character at a time? then do this instead:
var1 = translate(char,'A','3A'x, 'B','3B'x, 'C','3C'x);
Just remember that the macro executes before the data step starts, think of a macro as something that generate code statements.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
"var" is NOT a macro variable, but probably a data step variable. Its contents are NOT available for macro processing.
For the umpteenth time:
The macro PREprocessor is for generating dynamic code, NOT for handling data.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
If VAR is indeed a data step variable, DO NOT use macros.
%do i=1 %to %sysfunc(length(var));
should be a data step DO loop
do i=1 to length(var);
But, we here don't really know what VAR is, you haven't told us.
Please note: it is not a good idea to mix and match data step and macro code. While it can be done, you have to be absolutely sure you are performing data step functions on data step variables and macro functions on macro variables; and it should only be done when the data step by itself won't handle the situation without macros.
Paige Miller
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
I almost arrived with my solution.
for use correctly the length and the size of each observation, it was necessary to browse one by one.
I say almost because, when the observation size 1 of the variable var is greater than the size of the observation 2, the result in the new table test1 are same size and the processing of the observation 1 is "interrupted" and I do not understand why?
data test;
length var $10.;
var='test;;:ii<';
output;
var='testj;;';
output;
run;
option symbolgen mprint mlogic;
%macro tt();
data _null_;
set test;
call symputx('nbr', _n_);
run;
%put nbr=&nbr.;
%do j=1 %to &nbr.;
data _null_;
set test(obs=&j.);
call symputx('size', length(var));
run;
data test1;
set test(obs=&j.);
%do i=1 %to &size.;
%put i=&i;
lettre=substr(var,&i.,1);
type =indexc(lettre,'3A3B3C'x);
if type
then do; substr(var,&i.,1)=translate(lettre,'414243'x,'3A3B3C'x);
end;
else do; substr(var,&i.,1)=lettre;
end;
%end;
%end;
run;
%mend;
%tt;
Thank you
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Hi mansour_ib_sas
It will be a great help if you can give us an example of your wanted output. what should the output in test1 look like? - It seems you are trying to accomplish a relative simple task in a very complicated way that does not utilize the power of SAS.
From your example it seems that you examine each single character and translate ; to A, ; to B and < to C. If that is what you want, then the following code will do the job:
data test1; set test;
var = translate(var,'414243'x,'3A3B3C'x);
run;
Output:
testBBAiiC
testjBB
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
If you want to understand yout own code, you have to write it in a way that makes it easy to read and understand:
%macro tt();
data _null_;
set test;
call symputx('nbr', _n_);
run;
%put nbr=&nbr.;
%do j = 1 %to &nbr.;
data _null_;
set test(obs=&j.);
call symputx('size', length(var));
run;
data test1;
set test(obs=&j.);
%do i = 1 %to &size.;
%put i=&i;
lettre = substr(var,&i.,1);
type = indexc(lettre,'3A3B3C'x);
if type
then do;
substr(var,&i.,1)=translate(lettre,'414243'x,'3A3B3C'x);
end;
else do;
substr(var,&i.,1)=lettre;
end;
%end;
%end;
run;
%mend;
(Hint: do NOT use tabs in code; different systems and users have different tab settings, which skewer the display of code. Replace tabs with blanks, EG has a setting for that)
Most of your problems come from a misunderstanding what the obs= dataset option does. It does not read a single observation, but all observations up to the given number.
You also repeatedly overwrite test1 in the outer macro loop, so only the results of the last outer loop iteration will take effect. This last iteration is run with the length of the variable in the last observation of test. Since that is the shorter one, you have an incomplete execution of the translate for the first observation that is dealt with in the same step.
To determine the number of observations in a dataset, your method is inefficient:
data _null_;
set test;
call symputx('nbr', _n_);
run;
The whole dataset is read, and for every observation, a call symputx is made. If test is empty, no macro variable is created, and subsequent calls to it will fail. Do this instead:
data _null_;
call symputx('nbr', nobs);
stop;
set test nobs=nobs;
run;
A temporary variable nobs is created by the option of the set statement, and the data step stops immediately after the call symputx, without reading even one observation. OTOH, even with zero observations in the dataset, a correct value is set.
Bottom line: you still have a very rudimentary understanding of Base SAS code and the data step, so you are WAY out of your depth with dabbling in macro programming. Learn the basics of data step programming first before advancing into macro processing, and DO NOT abuse the macro preprocessor for data handling (which is what you are doing here). You will NOT learn anything useful that way, but only waste your time and ours.
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Note that your whole "experimental" logic can be solved without any macro code at all in one simple data step:
data test;
length var $10.;
var = 'test;;:ii<';
output;
var = 'testj;;';
output;
run;
data test1;
set test;
do i = 1 to length(var);
lettre = substr(var,i,1);
type = indexc(lettre,'3A3B3C'x);
if type
then do;
substr(var,i,1)=translate(lettre,'414243'x,'3A3B3C'x);
end;
else do;
substr(var,i,1) = lettre;
end;
end;
run;
- Mark as New
- Bookmark
- Subscribe
- Mute
- RSS Feed
- Permalink
- Report Inappropriate Content
Thank You,
Just whith data step, the code work.
I note
Sincerely