BookmarkSubscribeRSS Feed
_Dan_
Quartz | Level 8

Hi,

 

I've got to tidy up our Calendars, and so I am reading in various bits of data. One of these is a simple 'ls' output from Unix of the PPM Calendar folder.

 

I've noticed on occasion that the same calendar will exist a few times, but there's a version number I can extract that'll tell me which Calendar is the most recently utilised. Here's an example of the 'ls' output. I have highlighted the bit I need in bold.

 

 

/opt/sas/platform/pm//work/calendar/CAL_END_AR______400@username
/opt/sas/platform/pm//work/calendar/CAL_END_AR______401@username
/opt/sas/platform/pm//work/calendar/CAL_END_AR______403@username
/opt/sas/platform/pm//work/calendar/CAL_END_AR______404@username

 

 

I'm trying to use SCAN to obtain the version number by first telling it to get the string after '_____', and the string before '@'.

 

x=scan(scan(Text,2,"_____"),1,"@");

SCAN is simply finding the first "_" rather than the concurrent "______". I've tried the 'o', 'm' and 'f' modifiers to no avail.

 

Maybe SCAN isn't appropriate here, but does anyone know how I go about getting the 400, 401, 403, 404 etc?

 

I know I could reverse the SCAN and find the '@' and then the '_____' but the principle remains - it'll only be finding the '_____' because it contains a single '_', so I am more interested in learning how to force SCAN to search for a consecutive delimiter, rather than haphazardly stumbling across a workaround.

7 REPLIES 7
andreas_lds
Jade | Level 19

Multiple consecutive delimiters are treated as one delimiter, so you need:

 

Version = scan(scan(Text, 4, '_'), 1, '@');

Depending on the paths you have, using a regular expression could yield more stable results. Assuming that the version consists of numbers only:

VersionRx = prxchange('s/.*_(\d+)@/$1/', 1, Text);
_Dan_
Quartz | Level 8

Thanks for your reply.

 

The first example, using SCAN with the assumption of 4 underscores won't work I'm afraid, as the strings are not always delimited with the same volume of underscores. Actual Calendar names have been changed, but the construct is the same.

 

/opt/sas/platform/pm/work/calendar/PART1_PART2_____331@username
/opt/sas/platform/pm/work/calendar/PART1_PART2_PART3_____332@username
/opt/sas/platform/pm/work/calendar/PART1_PART2_25_____333@username

I did come across the prxchange answer elsewhere, but I may as well just reverse the SCAN using the 'b' modifier to get what I want. What I'm interested in is a way to tell SCAN that it must search for a concurrent volume of delimiters rather than a single one, but I suspect that is never the intended purpose, as a delimiter is naturally a single character.

fdsaaaa
Obsidian | Level 7

using regular expressions would be my recommendation.  

But if you want SAS to find consecutive delimiters here is a highly inefficient method to do what you are asking for

DATA A;
B ='/opt/sas/platform/pm//work/calendar/CAL_END_AR______400@username';
DO I = 1 TO count(b,'_');
C =         SCAN(B,I,'_');
D =         SCAN(B,I,'_','M');
IF C NE D THEN DO;
  WANT=SCAN(C,1,'@');
  PUT WANT=;
  STOP;
END;
END;
RUN;

 

ed_sas_member
Meteorite | Level 14
data want;
	set have;
	var2 = compress(var1,,'DK');
	/*or*/
	var3 = prxchange('s/.*____(\d+)@.*/$1/',1,var1);
run;
ed_sas_member
Meteorite | Level 14
data have;
	input var1:$80.;
	datalines;
/opt/sas/platform/pm//work/calendar/CAL_END_AR______400@username
/opt/sas/platform/pm//work/calendar/CAL_END_AR______401@username
/opt/sas/platform/pm//work/calendar/CAL_END_AR______403@username
/opt/sas/platform/pm//work/calendar/CAL_END_AR______404@username
;
run;

data want;
	set have;
	var4 = scan(scan(tranwrd(var1,'______','*'),2,'*'),1,'@');
run;
Astounding
PROC Star

Perhaps this isn't exceedingly ugly:

 

data want;
   set have;
   var2 = scan(substr(var1, index(var1, '____')), 1, '@');
run;
Tom
Super User Tom
Super User

SCAN() uses ANY of the characters as a delimiter. So listing the same character one or ten times does not make a difference.

But it looks like you pattern could be parsed by SCAN() if you just search from the words from the end instead of the beginning.

x=scan(Text,-2,'@_');

Word number -1 will be username and word number -2 will by 400.

SAS Innovate 2025: Register Now

Registration is now open for SAS Innovate 2025 , our biggest and most exciting global event of the year! Join us in Orlando, FL, May 6-9.
Sign up by Dec. 31 to get the 2024 rate of just $495.
Register now!

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
  • 7 replies
  • 2176 views
  • 3 likes
  • 6 in conversation