Remove values from a string SAS - sas

I have this column which i would wish to remain only the names and wish to remove everything after the ( s. May i know how could i achieve this?
Name Age
James 12
John (funny) 11
Jonathan 10
Alisa (134 cm) 12
Merlin (cheerful) 12
Jessica (hopeful) 12
Ali (quiet) 13
I have tried using functions such as compress but it still didnt work
data output;
length Name $30.;
infile datalines dlm=',';
input Name$ Age;
new = compress(name, '()');
datalines;
James,12
John (funny),11
Jonathan,10
Alisa (134 cm),12
Merlin (cheerful),12
Jessica (hopeful),12
Ali (quiet),13
;

Updating based on Tom's suggestion:
Use scan() and treat ( as a delimiter. This will pull all text before the first (.
new = scan(name, 1, '(', 'T')
The T option trims any trailing blanks.

You can use Perl regular expression patterns to replace parenthetical content with 'nothing'
name = prxchange ('s/\(.*?\)//', -1, name);

Related

name prefix and suffix removal SAS

I am looking for a way to remove a list of prefix and suffixes from the name variable
For example
under name I have
Mr. Walter White Jr.
I wish to keep just Walter White
I have list of prefixes and suffixes that I can use a reference
thanks in advance
Use regular expressions with your list to replace them with blank values.
data have;
infile datalines dlm='|';
length name $20.;
input name$;
datalines;
Mr. Walter White Jr.
Mrs. Skyler White
Dr. Saul Goodman
Mr. Jesse Pinkman
Mr. Gus Fring
;
run;
data want;
set have;
name = strip(prxchange('s/(Mr.|Jr|Dr)\.?//', -1, name) );
run;
Output:
name
Walter White
Skyler White
Saul Goodman
Jesse Pinkman
Gus Fring

Splitting a cell up using delimiters, but the delimiter is before the desired split location

I have some data in the form of a column in a dataset (named Person_details), where each has an unknown number of names, with the name (split up by spaces), followed by an underscore, followed by that persons identifier (7 characters).
Is there a way to split these entries up automatically, rather than repeatedly finding the position of the underscore, and then taking the substring before and after?
Person_details:
Evan Davies_123F323 Adam John Smith_342D427 Karl Marx_903C943
There are an unknown number of names in each cell, e.g. some have just one name and some have 20. Also complicated by the fact that some entries have middle name(s).
The ideal output would be in the form
Name Code
Evan Davies 123F323
Adam John Smith 342D427
Karl Marx 903C943
You could just use SCAN() instead.
data have;
string='Evan Davies_123F323 Adam Smith_342D427 Karl Marx_903C943';
length name $50 code $7 ;
do index=1 to countw(string,' ');
name = catx(' ',name,scan(string,index,' '));
if index(name,'_') then do;
code = scan(name,-1,'_');
name = substr(name,1,length(name)-length(code)-1);
output;
name=' ';
end;
end;
run;
Result
You can use a Perl regular expression (regex) to detect and extract pieces from patterned text. SAS routine PRXNEXT iterates through matches, and function PRXPOSN extracts pieces.
Example:
data have;
text = 'Evan Davies_123F323 Adam John Smith_342D427 Karl Marx_903C943';
run;
data want(keep=name code);
rx = prxparse('/(.+?)_(.{7}( |$))/');
set have;
start = 1;
stop = length(text);
do seq = 1 by 1;
call prxnext(rx,start,stop,text,position,length);
if position=0 then leave;
name = prxposn(rx,1,text);
code = prxposn(rx,2,text);
output;
end;
run;

Remove Middle Initial but not Middle Name from string

I'm trying to find a way to remove the Middle initial from a string containing the First name and middle initial (example "Mary A" needs to be "Mary").
However, I would need to keep the middle/second name if it was more than an initial (example "Mary Ann" would stay "Mary Ann").
Much thanks,
Matt
Try to use the function scan:
data test;
input name $20.;
cards;
Mary A
Anthony B
Mary Ann
Anthony Bernard
;
run;
data res;
set test;
if (length(scan(name,2))=1) then name=scan(name,1);
run;
As a result, you get:
Mary
Anthony
Mary Ann
Anthony Bernard
Here's an example of how to do this using regular expression substitution. I've used proc sql but this would also work in a data step:
data names;
input name & $5.;
cards;
Aa A
Aa Aa
Aaa A
;
run;
proc sql;
select prxchange('s/^(\w+)\s+\w\s*$/$1/',-1,name) from names;
quit;
The regex is built up as follows:
Capture the first word
Match a space, a single character, then any number of trailing spaces
If the whole expression is a match, return only the first word, otherwise return the whole input string unchanged.

Search for a string in a string

I have a data set which looks like the following, but containing thousands of rows.
Firstname Lastname Emailaddress
John Smith John.Smith#mail.com
Anna Blake Anna.Blake#mail.com
Susan Peterson 1962_Peterson_Susan#mail.com
David Anderson RandomEmail_1956#mail.com
I want to create a variable which tells me if the email address is containing the persons first or last name at all in disregard of position. If a match is found, the variable would return the value 1 and if no match is found it would return the value 0.
I have created the following logic which works for most cases.
Data CheckNames;
Set MyDataSet;
LenFM = Length(FirstName);
LenLM = Length(LastName);
If Substr(EmailAddress,1,LenFM) = FirstName or Substr(EmailAddress,1,LenLM) = LastName then Match = 1;
Else Match = 0;
run;
This logic would return Match = 1 for the first two results and Match = 0 for the last two. However I would like it to return Match = 1 for the third observation as well because it contains the name of the person.
My question is if there is a SAS command that lets me loop through all the observations in the variables Firstname and Lastname that then scans if the names are found in the variable EmailAddress.
I have tried with Find() and PrxMatch() but they both seem to require hard coded values, making them inefficient for this purpose.
Thank you!
Both FIND and PRXMATCH would work fine, and have no such requirement of hardcoded values. FIND works particularly well for this. Add the modifier t to tell it to trim the spaces from the firstname/lastname variable (or use the trim function).
data MyDataSet;
length firstname lastname emailaddress $50;
input Firstname $ Lastname $ Emailaddress $;
datalines;
John Smith John.Smith#mail.com
Anna Blake Anna.Blake#mail.com
Susan Peterson 1962_Peterson_Susan#mail.com
David Anderson RandomEmail_1956#mail.com
;;;;
run;
Data CheckNames;
Set MyDataSet;
Match = find(EmailAddress,Firstname,'t') | find(EmailAddress,LastName,'t');
run;
I use | there to OR the two find functions' values together, but you can do it more explicitly if you prefer.

Character value with embedded blanks with list input

I would like to read following instream datalines
datalines;
Smith,12,22,46,Green Hornets,AAA
FriedmanLi,23,19,25,High Volts,AAA
Jones,09,17,54,Las Vegas,AA
;
I employed while it read AAA items to team variables but not as div. And how should I place &(ampersand to read character with embedded blanks?)
data scores2;
infile datalines dlm=",";
input name : $10. score1-score3 team $20. div $;
datalines;
Smith,12,22,46,Green Hornets,AAA
FriedmanLi,23,19,25,High Volts,AAA
Jones,09,17,54,Las Vegas,AA
;
run;
Notice I have used : before team also ( well you have already used colon operator : for other variables , not sure why did you miss over here) As I have already mentioned in your other query, use : colon operator (tilde, dlm and colon format modifier in list input) which would tell SAS to use the informat supplied but to stop reading the value for this variable when a delimiter is encountered. Here as you had not used this operator , that is why SAS was trying to read 20 chars, even though
there was a delimiter in between.
Tested
data scores2;
infile datalines dlm=",";
input name : $10.
score1-score3
team : $20.
div : $3.;
datalines;
Smith,12,22,46,Green Hornets,AAA
FriedmanLi,23,19,25,High Volts,AAA
Jones,09,17,54,Las Vegas,AA
;
run;
Another way to do this that's often a bit easier to read is to use the informat statement.
data scores2;
infile datalines dlm=",";
informat name $10.
team $20.
div $4.;
input name $ score1-score3 team $ div $;
datalines;
Smith,12,22,46,Green Hornets,AAA
FriedmanLi,23,19,25,High Volts,AAA
Jones,09,17,54,Las Vegas,AA
;
run;
That accomplishes the same thing as using the colon (input name :$10.) but organizes it a bit more cleanly.
And just to be clear, embedded blanks are irrelevant in comma delimited input; '20'x (ie, space) is just another character when it's not the delimiter. What ampersand will do is addressed in this article, and more specifically, if space is the delmiiter it allows you to require two consecutive delimiters to end a field. Example:
data scores2;
infile datalines dlm=" ";
informat name $10.
team $20.
div $4.;
input name $ score1-score3 team & $ div $;
datalines;
Smith 12 22 46 Green Hornets AAA
FriedmanLi 23 19 25 High Volts AAA
Jones 09 17 54 Las Vegas AA
;
run;
Note the double space after all of the team names - that's required by the &. But this is only because delimiter is space (which is default, so if you removed the dlm=' ' it would also be needed.)