BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
chithra
Quartz | Level 8

Yes, working..Thanks.

But what happens when it comes to a sas table? It will not work 😞

 

Here it is a quoted string. But in my case these values are in a sas table.

Satish_Parida
Lapis Lazuli | Level 10

In that case this will also work.

 

There is no space timing, it is old school concatenation.

 

I have done the same thing in 2 steps just to demonstrate it works.

 

data have;
MEASURES1='cnt_pol_COMBINE sum_pol_COMBINE cnt_pol_QA sum_pol_QA cnt_pol_FO sum_pol_FO cnt_pol_FACNP sum_pol_FACNP cnt_pol_PQS sum_pol_PQS cnt_pol_SURPLUS1 sum_pol_SURPLUS1 cnt_pol_SURPLUS2 sum_pol_SURPLUS2 cnt_';
MEASURES2='pol_FACPROP sum_pol_FACPROP cnt_pol_OTHER sum_pol_OTHER cnt_ins_COMBINE sum_ins_COMBINE cnt_ins_QA sum_ins_QA cnt_ins_FO sum_ins_FO cnt_ins_FACNP sum_ins_FACNP cnt_ins_PQS sum_ins_PQS cnt_ins_SURPLUS1';
MEASURES3=' sum_ins_SURPLUS1 cnt_ins_SURPLUS2 sum_ins_SURPLUS2 cnt_ins_FACPROP sum_ins_FACPROP cnt_ins_OTHER sum_ins_OTHER';
run;

data want;
set have;
MEASURES4=MEASURES1||MEASURES2||MEASURES3;
run;

For real time,

1. if you know the number of vars you going to concatenate then define the length of final string in advance,

2. Please keep in mind the maximum length of character variables in this case, which is around 32000.

Tom
Super User Tom
Super User

@chithra wrote:

data macros(drop=b);

  length concatenate $100;

  do until (last.a);

    set a;

    by a;

    concatenate = cat(concatenate,b);

  end;

run;

 The above is a sample program where cat function is not working for me.


The CAT() function is doing what you told it to do.  You created CONCATENATE as length 100.  You that used CAT() function to create something that was LONGER than 100 characters and store it back into the 100 characters of CONCATENATE. Only the first 100 characters will fit so the value will always contain the 100 spaces that it started with.

 

WHAT output do you want?

Show both the input and output datasets in the form or working data steps.

Please use the {i} or SAS Running Man icons to post code otherwise the forum editor will re-format the code and any spaces you are trying to show

Astounding
PROC Star

Assuming

 

(1) Your incoming data set contains up to 5 observations, and

 

(2) You are only doing this for one variable (MEASURES3)

 

(3) The length of VALUE is $ 200:

 

data want;

set have end=done;

where name='MEASURES3';

length measures3 $ 1000;

retain measures3;

substr(measures3, 1 + 200*(_n_-1)) = value;

if done;

run;

 

The assumptions can be relaxed, but would require changes to the program.  So if the conditions are actually more complex than what you have specified so far, you need to spell them out.

 

************ EDITED:

 

Verified that these techniques work.  Sample test program:

 

data test;

input c $char8.;

retain all;

length all $ 24;

substr(all, 1 + (_n_-1)*8) = c;

datalines;

abc

12345678

def

;

 

proc print; run;

 

chithra
Quartz | Level 8
%let path=;
%let server_log=&path./server.log;
%let program_name=start_flexi_dash;

%macro multiple_xml;

	data log_file(keep=txt);
		length org_txt $10000 txt $10000;
		infile "&server_log.";
		input;
		org_txt= _infile_;

		if index(org_txt,"Request body-->") > 0 then
			do;
				txt=substr(org_txt,index(org_txt,"Request body-->")+15,length(org_txt));
				output;
			end;
	run;

	proc sql noprint;
		select count(*) into :count from log_file;
	quit;

	%do i=1 %to &count;

		data _null_;
			set log_file;

			if _N_= &i then
				do;
					file "%sysfunc(pathname(work))/xml_temp.xml";
					put txt;
					call symput("pgm_name",substr(txt,2,find(txt,">",2)-2 ));
				end;
		run;

		%if &pgm_name=&program_name %then
			%do;
				libname lib_xml xml  "%sysfunc(pathname(work))/xml_temp.xml" xmlconcatenate=yes;

				data xml_table;
					set lib_xml.parameters;
				run;

				proc transpose data=xml_table out=xml_trans;
					var _all_;
				run;

				data _null_;
					set xml_trans;
					call symputx(_NAME_,strip(col1),'g');
				run;

			%end;
	%end;
%mend;

%multiple_xml;

proc sql;
	create table vars as
		select name,value from dictionary.macros
			where scope eq 'GLOBAL';
quit;

proc sort data=vars;
	by name;
quit;

data macros(drop=value rename=(concatenate=value));
	length name $100 concatenate $32767;
	do until (last.name);
		set vars;
		by name;
		concatenate = concatenate||value;
	end;
run;

 

server.log file is below :

Request body--><start_flexi_dash><parameters><MEASURES3>cnt_pol_COMBINE sum_pol_COMBINE cnt_pol_QA sum_pol_QA cnt_pol_FO sum_pol_FO cnt_pol_FACNP sum_pol_FACNP cnt_pol_PQS sum_pol_PQS cnt_pol_SURPLUS1 sum_pol_SURPLUS1 cnt_pol_SURPLUS2 sum_pol_SURPLUS2 cnt_pol_FACPROP sum_pol_FACPROP cnt_pol_OTHER sum_pol_OTHER cnt_ins_COMBINE sum_ins_COMBINE cnt_ins_QA sum_ins_QA cnt_ins_FO sum_ins_FO cnt_ins_FACNP sum_ins_FACNP cnt_ins_PQS sum_ins_PQS cnt_ins_SURPLUS1 sum_ins_SURPLUS1 cnt_ins_SURPLUS2 sum_ins_SURPLUS2 cnt_ins_FACPROP sum_ins_FACPROP cnt_ins_OTHER sum_ins_OTHER</MEASURES3><OE_ID_COUNT>1</OE_ID_COUNT></parameters></start_flexi_dash>

 

 

This is my exact program will look like.

please copy the contents and save it as server.log and put the path of the file in the above of the sas program.

 

The || operator here returns null value.

 

Can you please check?

chithra
Quartz | Level 8

concatenate = strip(concatenate)||value;

 

Finally This works for me.

 

Thank you all for your help.

Astounding
PROC Star

It works a lot of the time.  It fails when the last character of VALUE is a blank, and then you need to add another VALUE after that.

chithra
Quartz | Level 8

yes, It fails when the last character of VALUE is a blank 😞

Is there anyway to solve this?

Tom
Super User Tom
Super User

SAS stores character variables as fixed length.  So short strings are padded with spaces.

The LENGTH() function will return the location of the last non space.

If you want to keep track of a specific number of meaningful trailing spaces then you will need to store your a actual length in a separate field.

 

data test;
  length chlen 8 chstr $50 ;
  input chlen 1-5 chstr $varying50. chlen ;
cards;
00009  Leading
00010Trailing
00005Short
;

data want ;
  length newlen 8 new $200 ;
  retain newlen 0 new ;
  set test;
  new = substrn(new,1,newlen)||chstr ;
  newlen + chlen ;
  put '|' new $varying200. newlen '|';
run;
 71         data want ;
 72           length newlen 8 new $200 ;
 73           retain newlen 0 new ;
 74           set test;
 75           /*if newlen=0 then new=chstr;
 76           else */new = substrn(new,1,newlen)||chstr ;
 77           newlen + chlen ;
 78           put '|' new $varying200. newlen '|';
 79         run;
 
 |  Leading|
 |  LeadingTrailing  |
 |  LeadingTrailing  Short|
 NOTE: There were 3 observations read from the data set WORK.TEST.
chithra
Quartz | Level 8

Many Thanks.

 

This Works. I use lengthc() function to get the length of the string including trailing blanks.

 

ksj
Fluorite | Level 6 ksj
Fluorite | Level 6

Sorry,came across this while chasing another problem..

lengthc() returns length of the string including trailing blanks. However, for character fields in SAS datasets, lengthc() always returns the length of the field defined in the SAS dataset. This is because SAS stores the value by padding it with blanks to fill the defined length. 

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 25 replies
  • 5373 views
  • 2 likes
  • 7 in conversation